From 517a5473b47c270da6c196e62ea68d841428e7d8 Mon Sep 17 00:00:00 2001 From: Balint Reczey Date: Sun, 28 Jun 2015 12:44:32 -0400 Subject: [PATCH] Import gpac_0.5.2-426-gc5ad4e4+dfsg5.orig.tar.xz [dgit import orig gpac_0.5.2-426-gc5ad4e4+dfsg5.orig.tar.xz] --- .gitattributes | 19 + .travis.yml | 19 + AUTHORS | 11 + BUGS | 9 + COPYING | 504 + Changelog | 732 + Clean.bat | 23 + INSTALLME | 69 + Makefile | 287 + README | 18 + TODO | 7 + applications/Makefile | 77 + applications/dashcast/Makefile | 77 + applications/dashcast/audio_data.c | 97 + applications/dashcast/audio_data.h | 142 + applications/dashcast/audio_decoder.c | 399 + applications/dashcast/audio_decoder.h | 100 + applications/dashcast/audio_encoder.c | 347 + applications/dashcast/audio_encoder.h | 64 + applications/dashcast/audio_muxer.c | 462 + applications/dashcast/audio_muxer.h | 131 + applications/dashcast/circular_buffer.c | 263 + applications/dashcast/circular_buffer.h | 246 + applications/dashcast/cmd_data.c | 920 + applications/dashcast/cmd_data.h | 137 + applications/dashcast/controler.c | 1599 + applications/dashcast/controler.h | 100 + applications/dashcast/dashcast.c | 64 + applications/dashcast/libav_compat.h | 56 + applications/dashcast/message_queue.c | 120 + applications/dashcast/message_queue.h | 58 + applications/dashcast/register.c | 85 + applications/dashcast/register.h | 50 + applications/dashcast/task.c | 69 + applications/dashcast/task.h | 69 + applications/dashcast/video_data.c | 93 + applications/dashcast/video_data.h | 169 + applications/dashcast/video_decoder.c | 402 + applications/dashcast/video_decoder.h | 97 + applications/dashcast/video_encoder.c | 290 + applications/dashcast/video_encoder.h | 63 + applications/dashcast/video_muxer.c | 924 + applications/dashcast/video_muxer.h | 114 + applications/dashcast/video_scaler.c | 273 + applications/dashcast/video_scaler.h | 168 + applications/generators/MPEG4/MPEG4Gen.dsp | 98 + applications/generators/MPEG4/MPEG4Gen.dsw | 29 + applications/generators/MPEG4/Makefile | 52 + applications/generators/MPEG4/main.c | 1862 + applications/generators/MPEG4/skip.txt | 181 + applications/generators/MPEG4/templates1.txt | 1292 + applications/generators/MPEG4/templates10.txt | 53 + applications/generators/MPEG4/templates2.txt | 592 + applications/generators/MPEG4/templates3.txt | 123 + applications/generators/MPEG4/templates4.txt | 129 + applications/generators/MPEG4/templates5.txt | 561 + applications/generators/MPEG4/templates6.txt | 242 + applications/generators/MPEG4/templates7.txt | 235 + applications/generators/MPEG4/templates8.txt | 124 + applications/generators/MPEG4/templates9.txt | 68 + applications/generators/Makefile | 26 + applications/generators/SVG/Makefile | 57 + applications/generators/SVG/SVGGen.dsp | 126 + applications/generators/SVG/SVGGen.dsw | 29 + .../generators/SVG/Tiny-1.2-NG/Tiny-1.2.nvdl | 35 + .../generators/SVG/Tiny-1.2-NG/Tiny-1.2.rng | 55 + .../generators/SVG/Tiny-1.2-NG/animate.rng | 334 + .../SVG/Tiny-1.2-NG/animation-element.rng | 59 + .../generators/SVG/Tiny-1.2-NG/audio.rng | 51 + .../SVG/Tiny-1.2-NG/conditional.rng | 65 + .../SVG/Tiny-1.2-NG/contenttype-attrib.rng | 22 + .../SVG/Tiny-1.2-NG/coordinate-attrib.rng | 42 + .../SVG/Tiny-1.2-NG/core-attrib.rng | 67 + .../generators/SVG/Tiny-1.2-NG/datatypes.rng | 145 + .../generators/SVG/Tiny-1.2-NG/discard.rng | 45 + .../SVG/Tiny-1.2-NG/extensibility.rng | 44 + .../SVG/Tiny-1.2-NG/extresources-attrib.rng | 22 + .../SVG/Tiny-1.2-NG/flowable-text-tiny.rng | 118 + .../SVG/Tiny-1.2-NG/focus-attrib.rng | 86 + .../generators/SVG/Tiny-1.2-NG/font-tiny.rng | 349 + .../SVG/Tiny-1.2-NG/gradient-tiny.rng | 156 + .../SVG/Tiny-1.2-NG/graphics-attrib.rng | 109 + .../generators/SVG/Tiny-1.2-NG/handler.rng | 53 + .../generators/SVG/Tiny-1.2-NG/headers.rng | 67 + .../generators/SVG/Tiny-1.2-NG/hyperlink.rng | 47 + .../generators/SVG/Tiny-1.2-NG/image.rng | 53 + .../generators/SVG/Tiny-1.2-NG/laser-ext.rng | 146 + .../SVG/Tiny-1.2-NG/media-attrib.rng | 40 + .../SVG/Tiny-1.2-NG/opacity-attrib-tiny.rng | 44 + .../SVG/Tiny-1.2-NG/paint-attrib-tiny.rng | 113 + .../generators/SVG/Tiny-1.2-NG/prefetch.rng | 60 + .../generators/SVG/Tiny-1.2-NG/script.rng | 44 + .../generators/SVG/Tiny-1.2-NG/shapes.rng | 230 + .../generators/SVG/Tiny-1.2-NG/solidcolor.rng | 65 + .../SVG/Tiny-1.2-NG/structure-tiny.rng | 257 + .../generators/SVG/Tiny-1.2-NG/text-tiny.rng | 213 + .../SVG/Tiny-1.2-NG/transform-attrib.rng | 25 + .../Tiny-1.2-NG/vectoreffects-attrib-tiny.rng | 26 + .../generators/SVG/Tiny-1.2-NG/video.rng | 80 + .../SVG/Tiny-1.2-NG/viewport-attrib-tiny.rng | 45 + .../SVG/Tiny-1.2-NG/xlink-attrib.rng | 123 + .../generators/SVG/Tiny-1.2-NG/xml-events.rng | 84 + applications/generators/SVG/html.c | 151 + applications/generators/SVG/laser.c | 267 + applications/generators/SVG/main.c | 953 + applications/generators/SVG/svggen.h | 195 + applications/generators/SVG/v1.c | 608 + applications/generators/SVG/v2.c | 463 + applications/generators/SVG/v3.c | 295 + applications/generators/X3D/Makefile | 52 + applications/generators/X3D/X3DGen.dsp | 98 + applications/generators/X3D/X3DGen.dsw | 29 + applications/generators/X3D/main.c | 1279 + applications/generators/X3D/skip.txt | 130 + applications/generators/X3D/templates_X3D.txt | 1644 + applications/m3u82mpd/m3u82mpd.vcproj | 183 + applications/m3u82mpd/main.c | 122 + applications/mp42avi/Makefile | 48 + applications/mp42avi/main.c | 785 + applications/mp42ts/Makefile | 50 + applications/mp42ts/main.c | 2755 + applications/mp42ts/mp42ts.h | 202 + applications/mp4box/Makefile | 88 + applications/mp4box/filedump.c | 2956 ++ applications/mp4box/fileimport.c | 2782 + applications/mp4box/live.c | 943 + applications/mp4box/main.c | 4680 ++ applications/mp4box/wrapper.c | 104 + applications/mp4client/Makefile | 64 + applications/mp4client/carbon_events.c | 109 + applications/mp4client/extract.c | 962 + applications/mp4client/main.c | 2934 ++ applications/mp4client/mp4client.rc | 72 + applications/mp4client/resource.h | 18 + applications/testapps/bmp4demux/Makefile | 50 + applications/testapps/bmp4demux/bmp4demux.sln | 20 + .../testapps/bmp4demux/bmp4demux.vcxproj | 191 + .../bmp4demux/bmp4demux.vcxproj.filters | 137 + applications/testapps/bmp4demux/build.sh | 2 + applications/testapps/bmp4demux/main.c | 93 + applications/testapps/broadcaster/Makefile | 34 + .../testapps/broadcaster/RTP_serv_generator.c | 286 + .../testapps/broadcaster/RTP_serv_generator.h | 66 + .../broadcaster/RTP_serv_packetizer.c | 92 + .../broadcaster/RTP_serv_packetizer.h | 13 + .../testapps/broadcaster/RTP_serv_sender.c | 83 + .../testapps/broadcaster/RTP_serv_sender.h | 14 + .../testapps/broadcaster/broadcaster.c | 546 + .../testapps/broadcaster/broadcaster.dsp | 146 + .../testapps/broadcaster/broadcaster.h | 85 + .../broadcaster/broadcaster_config.cfg | 16 + applications/testapps/broadcaster/debug.c | 24 + applications/testapps/broadcaster/debug.h | 18 + applications/testapps/broadcaster/france.mp4 | Bin 0 -> 9131 bytes .../testapps/broadcaster/meteo_local.xmt | 393 + .../testapps/broadcaster/sdp_generator.c | 67 + .../testapps/broadcaster/sdp_generator.h | 29 + applications/testapps/dmbrs/dmbrs.dsp | 90 + applications/testapps/dmbrs/main.c | 251 + applications/testapps/fmp4demux/Makefile | 50 + applications/testapps/fmp4demux/build.sh | 2 + applications/testapps/fmp4demux/fmp4demux.sln | 20 + .../testapps/fmp4demux/fmp4demux.vcxproj | 190 + .../fmp4demux/fmp4demux.vcxproj.filters | 140 + applications/testapps/fmp4demux/main.c | 315 + applications/testapps/hevcbench/defbench.h | 111 + .../testapps/hevcbench/hevcbench.vcxproj | 262 + applications/testapps/hevcbench/main.c | 858 + applications/testapps/largefile/largefile.dsp | 102 + applications/testapps/largefile/largefile.dsw | 44 + applications/testapps/largefile/main.c | 85 + .../testapps/loadcompare/LoadCompare.dsp | 112 + applications/testapps/loadcompare/Makefile | 55 + .../testapps/loadcompare/loadcompare.c | 698 + applications/testapps/mp42ts/mp42ts.vcproj | 217 + applications/testapps/mpedemux/Makefile | 65 + applications/testapps/mpedemux/main.c | 103 + applications/testapps/mpedemux/mpedemux.dsp | 90 + applications/testapps/mpeg2ts/main.c | 88 + applications/testapps/mpeg2ts/mpeg2ts.dsp | 100 + applications/testapps/segmp4demux/Makefile | 50 + applications/testapps/segmp4demux/build.sh | 2 + applications/testapps/segmp4demux/main.c | 139 + .../testapps/segmp4demux/segmp4demux.sln | 20 + .../testapps/segmp4demux/segmp4demux.vcxproj | 191 + .../segmp4demux/segmp4demux.vcxproj.filters | 137 + applications/testapps/svg2bifs/main.c | 1047 + applications/testapps/svg2bifs/svg2bifs.dsp | 90 + applications/ts2hds/Makefile | 50 + applications/ts2hds/f4m.c | 173 + applications/ts2hds/f4v.c | 185 + applications/ts2hds/main.c | 304 + applications/ts2hds/ts2hds.h | 48 + applications/udptsseg/Makefile | 70 + applications/udptsseg/main.c | 314 + applications/udptsseg/udptsseg.dsp | 94 + applications/udptsseg/udptsseg.vcproj | 213 + .../release/install/archive.bat | 16 + .../release/install/build_installer.bat | 42 + .../release/install/gpac.inf | 148 + .../release/install/readme.txt | 6 + configure | 3361 ++ doc/CODING_STYLE | 133 + doc/GPAC UPnP.doc | Bin 0 -> 81408 bytes doc/INSTALL.gcc | 116 + doc/INSTALL.gpe | 100 + doc/INSTALL.symbian | 84 + doc/INSTALL.w32 | 217 + doc/INSTALL.wCE | 134 + doc/ISO 639-2 codes.txt | 487 + doc/SceneGenerators | 148 + doc/configuration.html | 903 + doc/doxyfile | 2316 + doc/doxyfile-full | 2321 + doc/gpac.mp4 | Bin 0 -> 2688 bytes doc/ipmpx_syntax.bt | 237 + doc/man/gpac.1 | 447 + doc/man/mp42avi.1 | 69 + doc/man/mp4box.1 | 808 + doc/man/mp4client.1 | 301 + doc/osmo4.ico | Bin 0 -> 15086 bytes generate_installer.bat | 100 + gpac.spec | 100 + gui/extensions/H2B2VS/H2B2VS.png | Bin 0 -> 22850 bytes gui/extensions/H2B2VS/h2b2vs.js | 392 + gui/extensions/H2B2VS/init.js | 16 + gui/extensions/H2B2VS/logo_hd.png | Bin 0 -> 16123 bytes gui/extensions/H2B2VS/logo_uhd.png | Bin 0 -> 50515 bytes .../player/applications-multimedia.svg | 498 + gui/extensions/player/fileopen.js | 242 + gui/extensions/player/init.js | 15 + gui/extensions/player/player.js | 1436 + gui/extensions/player/playlist.js | 327 + gui/extensions/player/stats.js | 606 + .../widget_manager/applications-system.svg | 247 + gui/extensions/widget_manager/init.js | 927 + gui/gui.bt | 42 + gui/gui.js | 295 + gui/gui_old.bt | 42 + gui/gui_old.js | 2104 + gui/gwlib.js | 3502 ++ gui/icons/add.svg | 12 + gui/icons/app.svg | 35 + gui/icons/audio.svg | 19 + gui/icons/audio_full.svg | 26 + gui/icons/audio_mute.svg | 12 + gui/icons/check.svg | 11 + gui/icons/close.svg | 16 + gui/icons/cross.svg | 13 + gui/icons/down.svg | 9 + gui/icons/expand.svg | 26 + gui/icons/file.svg | 10 + gui/icons/film.svg | 27 + gui/icons/folder.svg | 15 + gui/icons/harddrive.svg | 14 + gui/icons/heart.svg | 8 + gui/icons/home.svg | 11 + gui/icons/image.svg | 14 + gui/icons/info.svg | 14 + gui/icons/laptop.svg | 16 + gui/icons/left.svg | 9 + gui/icons/list.svg | 20 + gui/icons/live.svg | 21 + gui/icons/media_next.svg | 12 + gui/icons/media_prev.svg | 12 + gui/icons/monitor.svg | 11 + gui/icons/more.svg | 9 + gui/icons/musical.svg | 14 + gui/icons/navigation.svg | 17 + gui/icons/network.svg | 27 + gui/icons/next.svg | 11 + gui/icons/osmo.svg | 26 + gui/icons/overflowing.svg | 30 + gui/icons/pause.svg | 12 + gui/icons/pl_next.svg | 16 + gui/icons/pl_prev.svg | 16 + gui/icons/play.svg | 10 + gui/icons/play_loop.svg | 16 + gui/icons/play_shuffle.svg | 17 + gui/icons/play_single.svg | 12 + gui/icons/power.svg | 14 + gui/icons/previous.svg | 11 + gui/icons/remove.svg | 10 + gui/icons/resize.svg | 14 + gui/icons/rewind.svg | 11 + gui/icons/right.svg | 9 + gui/icons/seek_forward.svg | 11 + gui/icons/shrink.svg | 55 + gui/icons/sort.svg | 25 + gui/icons/speed.svg | 26 + gui/icons/star.svg | 11 + gui/icons/stop.svg | 10 + gui/icons/stop2.svg | 10 + gui/icons/trash.svg | 16 + gui/icons/tray.svg | 14 + gui/icons/tv.svg | 21 + gui/icons/up.svg | 9 + gui/icons/world.svg | 64 + gui/iphone_wm_gui.js | 1651 + gui/iphone_wm_gui.svg | 552 + gui/mpegu-wm.bt | 31 + gui/mpegu-wm.xmt | 69 + gui/tv_wm_gui.js | 485 + gui/tv_wm_gui.svg | 31 + gui/webvtt-renderer.js | 281 + include/gpac/ait.h | 242 + include/gpac/avparse.h | 262 + include/gpac/base_coding.h | 106 + include/gpac/bifs.h | 107 + include/gpac/bitstream.h | 538 + include/gpac/cache.h | 247 + include/gpac/color.h | 286 + include/gpac/compositor.h | 177 + include/gpac/config_file.h | 235 + include/gpac/configuration.h | 284 + include/gpac/constants.h | 668 + include/gpac/crypt.h | 165 + include/gpac/dash.h | 410 + include/gpac/download.h | 576 + include/gpac/dsmcc.h | 665 + include/gpac/dvb_mpe.h | 46 + include/gpac/esi.h | 198 + include/gpac/events.h | 325 + include/gpac/events_constants.h | 514 + include/gpac/filestreamer.h | 121 + include/gpac/html5_media.h | 363 + include/gpac/html5_mse.h | 231 + include/gpac/ietf.h | 1352 + include/gpac/internal/avilib.h | 439 + include/gpac/internal/bifs_dev.h | 242 + include/gpac/internal/bifs_tables.h | 835 + include/gpac/internal/camera.h | 193 + include/gpac/internal/compositor_dev.h | 1458 + include/gpac/internal/crypt_dev.h | 158 + include/gpac/internal/dvb_mpe_dev.h | 265 + include/gpac/internal/ietf_dev.h | 346 + include/gpac/internal/isomedia_dev.h | 4244 ++ include/gpac/internal/laser_dev.h | 342 + include/gpac/internal/m3u8.h | 126 + include/gpac/internal/media_dev.h | 501 + include/gpac/internal/mesh.h | 302 + include/gpac/internal/mpd.h | 418 + include/gpac/internal/odf_dev.h | 365 + include/gpac/internal/odf_parse_common.h | 44 + include/gpac/internal/ogg.h | 213 + include/gpac/internal/reedsolomon.h | 78 + include/gpac/internal/scenegraph_dev.h | 1119 + include/gpac/internal/smjs_api.h | 358 + include/gpac/internal/swf_dev.h | 407 + include/gpac/internal/terminal_dev.h | 1271 + include/gpac/internal/vobsub.h | 83 + include/gpac/ismacryp.h | 151 + include/gpac/iso639.h | 73 + include/gpac/isomedia.h | 2415 + include/gpac/laser.h | 88 + include/gpac/list.h | 245 + include/gpac/map.h | 213 + include/gpac/maths.h | 1036 + include/gpac/media_tools.h | 531 + include/gpac/mediaobject.h | 197 + include/gpac/module.h | 372 + include/gpac/modules/audio_out.h | 190 + include/gpac/modules/codec.h | 357 + include/gpac/modules/font.h | 127 + include/gpac/modules/hardcoded_proto.h | 70 + include/gpac/modules/ipmp.h | 144 + include/gpac/modules/js_usr.h | 70 + include/gpac/modules/raster2d.h | 267 + include/gpac/modules/service.h | 783 + include/gpac/modules/term_ext.h | 112 + include/gpac/modules/video_out.h | 239 + include/gpac/mpeg4_odf.h | 1854 + include/gpac/mpegts.h | 1361 + include/gpac/network.h | 507 + include/gpac/nodes_mpeg4.h | 3338 ++ include/gpac/nodes_svg.h | 532 + include/gpac/nodes_x3d.h | 2020 + include/gpac/nodes_xbl.h | 70 + include/gpac/options.h | 316 + include/gpac/path2d.h | 616 + include/gpac/ringbuffer.h | 94 + include/gpac/rtp_streamer.h | 162 + include/gpac/scene_engine.h | 206 + include/gpac/scene_manager.h | 493 + include/gpac/scenegraph.h | 786 + include/gpac/scenegraph_svg.h | 656 + include/gpac/scenegraph_vrml.h | 678 + include/gpac/setup.h | 553 + include/gpac/svg_types.h | 899 + include/gpac/sync_layer.h | 145 + include/gpac/term_info.h | 180 + include/gpac/terminal.h | 221 + include/gpac/thread.h | 291 + include/gpac/token.h | 107 + include/gpac/tools.h | 1004 + include/gpac/unicode.h | 54 + include/gpac/user.h | 116 + include/gpac/utf.h | 100 + include/gpac/version.h | 46 + include/gpac/webvtt.h | 85 + include/gpac/xml.h | 288 + include/win32/inttypes.h | 21 + include/win32/stdint.h | 17 + include/wince/errno.h | 104 + mkdmg.sh | 130 + modules/Makefile | 173 + modules/aac_in/Makefile | 62 + modules/aac_in/aac_in.c | 995 + modules/aac_in/faad_dec.c | 491 + modules/ac3_in/Makefile | 59 + modules/ac3_in/ac3_in.c | 705 + modules/ac3_in/liba52_dec.c | 374 + modules/alsa/Makefile | 44 + modules/alsa/alsa.c | 379 + modules/amr_dec/Makefile | 72 + modules/amr_dec/amr_dec.c | 334 + modules/amr_dec/amr_in.c | 606 + modules/amr_dec/amr_nb/typedefs.h | 195 + modules/amr_dec/amr_nb_api.h | 61 + modules/amr_float_dec/Makefile | 62 + modules/amr_float_dec/amr_api.h | 35 + modules/amr_float_dec/amr_float_dec.c | 353 + modules/audio_filter/Makefile | 42 + modules/audio_filter/audio_filter.c | 288 + modules/avcap/Makefile | 46 + modules/avcap/avcap.cpp | 508 + modules/bifs_dec/Makefile | 50 + modules/bifs_dec/bifs_dec.c | 216 + modules/ctx_load/Makefile | 49 + modules/ctx_load/ctx_load.c | 836 + modules/dektec_out/Makefile | 58 + modules/dektec_out/dektec_video.cpp | 361 + modules/demo_is/Makefile | 46 + modules/demo_is/demo-sensor.bt | 86 + modules/demo_is/demo_is.c | 104 + modules/directfb_out/Makefile | 48 + modules/directfb_out/directfb_out.c | 400 + modules/directfb_out/directfb_out.h | 74 + modules/directfb_out/directfb_wrapper.c | 930 + modules/droid_audio/droidaudio.c | 503 + modules/droid_audio/javaenv.c | 49 + modules/droid_audio/javaenv.h | 34 + modules/droid_cam/droid_cam.c | 747 + modules/droid_mpegv/droid_mpegv.c | 493 + modules/droid_out/droid_vout-bitmap.c | 219 + modules/droid_out/droid_vout.c | 712 + modules/dummy_in/Makefile | 49 + modules/dummy_in/dummy_in.c | 519 + modules/dx_hw/Makefile | 59 + modules/dx_hw/collide.cur | Bin 0 -> 2238 bytes modules/dx_hw/copy_pixels.c | 598 + modules/dx_hw/dx_2d.c | 856 + modules/dx_hw/dx_audio.c | 482 + modules/dx_hw/dx_hw.h | 234 + modules/dx_hw/dx_hw.rc | 75 + modules/dx_hw/dx_video.c | 907 + modules/dx_hw/dx_window.c | 1301 + modules/dx_hw/hand.cur | Bin 0 -> 2238 bytes modules/dx_hw/resource.h | 23 + modules/epoc_hw/epoc_aout.cpp | 380 + modules/epoc_hw/epoc_codec.cpp | 427 + modules/epoc_hw/epoc_vout.cpp | 555 + modules/ffmpeg_in/Makefile | 77 + modules/ffmpeg_in/ffmpeg_decode.c | 1444 + modules/ffmpeg_in/ffmpeg_demux.c | 1038 + modules/ffmpeg_in/ffmpeg_in.h | 271 + modules/ffmpeg_in/ffmpeg_load.c | 81 + modules/freenect/Makefile | 54 + modules/freenect/freenect.c | 593 + modules/ft_font/Makefile | 57 + modules/ft_font/ft_font.c | 770 + modules/ft_font/ft_font.h | 30 + modules/gapi/gapi.cpp | 1675 + modules/gapi/gapi.h | 108 + modules/gdip_raster/gdip_font.cpp | 407 + modules/gdip_raster/gdip_grad.cpp | 407 + modules/gdip_raster/gdip_priv.h | 205 + modules/gdip_raster/gdip_rend.cpp | 499 + modules/gdip_raster/gdip_texture.cpp | 489 + modules/gpac_js/Makefile | 63 + modules/gpac_js/gpac_js.c | 2137 + modules/hyb_in/Makefile | 46 + modules/hyb_in/fm_fake_pull.c | 220 + modules/hyb_in/fm_fake_push.c | 329 + modules/hyb_in/fm_mmbtools.c | 29 + modules/hyb_in/hyb_in.c | 312 + modules/hyb_in/hyb_in.h | 96 + modules/img_in/Makefile | 78 + modules/img_in/bmp_dec.c | 210 + modules/img_in/img_dec.c | 159 + modules/img_in/img_in.c | 448 + modules/img_in/img_in.h | 107 + modules/img_in/jp2_dec.c | 469 + modules/img_in/jpeg_dec.c | 156 + modules/img_in/png_dec.c | 181 + modules/ios_cam/CameraObject.h | 64 + modules/ios_cam/CameraObject.m | 170 + modules/ios_cam/cam_wrap.h | 55 + modules/ios_cam/cam_wrap.m | 82 + modules/ios_cam/ios_cam.c | 435 + modules/ios_mpegv/SensorAcces.m | 209 + modules/ios_mpegv/SensorAccess.h | 34 + modules/ios_mpegv/ios_mpegv-Prefix.pch | 7 + modules/ios_mpegv/ios_mpegv.c | 306 + modules/ios_mpegv/sensor_wrap.h | 43 + modules/ismacryp/Makefile | 48 + modules/ismacryp/isma_ea.c | 626 + modules/isom_in/Makefile | 49 + modules/isom_in/isom_cache.c | 286 + modules/isom_in/isom_in.h | 163 + modules/isom_in/load.c | 256 + modules/isom_in/read.c | 1259 + modules/isom_in/read_ch.c | 875 + modules/jack/Makefile | 42 + modules/jack/jack.c | 572 + modules/laser_dec/Makefile | 50 + modules/laser_dec/laser_dec.c | 198 + modules/libplayer/Makefile | 43 + modules/libplayer/libplayer.c | 664 + modules/modules_export.cpp | 38 + modules/mp3_in/Makefile | 65 + modules/mp3_in/mad_dec.c | 372 + modules/mp3_in/mp3_in.c | 781 + modules/mpd_in/Makefile | 46 + modules/mpd_in/mpd_in.c | 1457 + modules/mpegts_in/Makefile | 50 + modules/mpegts_in/mpegts_in.c | 1710 + modules/mse_in/Makefile | 59 + modules/mse_in/mse_in.c | 379 + modules/odf_dec/Makefile | 49 + modules/odf_dec/odf_dec.c | 323 + modules/ogg/Makefile | 83 + modules/ogg/ogg_in.c | 1011 + modules/ogg/ogg_in.h | 64 + modules/ogg/ogg_load.c | 162 + modules/ogg/theora_dec.c | 235 + modules/ogg/vorbis_dec.c | 278 + modules/opencv_is/Makefile | 49 + modules/opencv_is/demo-sensor.bt | 93 + .../haarcascade_frontalface_default.xml | 35712 +++++++++++++ modules/opencv_is/opencv_is.c | 221 + modules/openhevc_dec/Makefile | 49 + modules/openhevc_dec/openhevc_dec.c | 685 + modules/opensvc_dec/Makefile | 45 + modules/opensvc_dec/opensvc_dec.c | 458 + modules/osd/Makefile | 47 + modules/osd/osd.c | 306 + modules/oss_audio/Makefile | 55 + modules/oss_audio/oss.c | 286 + modules/platinum/GPACFileMediaServer.cpp | 580 + modules/platinum/GPACFileMediaServer.h | 139 + modules/platinum/GPACMediaController.cpp | 362 + modules/platinum/GPACMediaController.h | 139 + modules/platinum/GPACMediaRenderer.cpp | 600 + modules/platinum/GPACMediaRenderer.h | 102 + modules/platinum/GPACPlatinum.cpp | 1740 + modules/platinum/GPACPlatinum.h | 158 + modules/platinum/GenericDevice.cpp | 1002 + modules/platinum/GenericDevice.h | 207 + modules/platinum/Makefile | 63 + modules/pulseaudio/Makefile | 42 + modules/pulseaudio/pulseaudio.c | 346 + modules/raw_out/Makefile | 58 + modules/raw_out/raw_video.c | 293 + modules/redirect_av/Makefile | 53 + modules/redirect_av/ffmpeg_ts_muxer.c | 407 + modules/redirect_av/gpac_ts_muxer.c | 178 + modules/redirect_av/redirect_av.c | 851 + modules/redirect_av/ts_muxer.h | 119 + modules/rtp_in/Makefile | 51 + modules/rtp_in/rtp_in.c | 920 + modules/rtp_in/rtp_in.h | 378 + modules/rtp_in/rtp_session.c | 412 + modules/rtp_in/rtp_signaling.c | 855 + modules/rtp_in/rtp_stream.c | 580 + modules/rtp_in/sdp_fetch.c | 187 + modules/rtp_in/sdp_load.c | 570 + modules/rvc_dec/Makefile | 46 + modules/rvc_dec/rvc_dec.c | 499 + modules/saf_in/Makefile | 51 + modules/saf_in/saf_in.c | 625 + modules/sdl_out/Makefile | 48 + modules/sdl_out/audio.c | 247 + modules/sdl_out/cursors.c | 63 + modules/sdl_out/sdl_out.c | 96 + modules/sdl_out/sdl_out.h | 126 + modules/sdl_out/video.c | 2173 + modules/sdl_out/video2d.c | 29 + modules/soft_raster/Makefile | 55 + modules/soft_raster/ftgrays.c | 779 + modules/soft_raster/rast_soft.h | 367 + modules/soft_raster/raster_565.c | 495 + modules/soft_raster/raster_argb.c | 730 + modules/soft_raster/raster_load.c | 106 + modules/soft_raster/raster_rgb.c | 402 + modules/soft_raster/stencil.c | 985 + modules/soft_raster/surface.c | 662 + modules/svg_in/Makefile | 57 + modules/svg_in/svg_in.c | 461 + modules/timedtext/Makefile | 50 + modules/timedtext/timedtext_dec.c | 1247 + modules/timedtext/timedtext_in.c | 440 + modules/ui_rec/Makefile | 52 + modules/ui_rec/readme.txt | 14 + modules/ui_rec/ui_rec.c | 252 + modules/validator/Makefile | 49 + modules/validator/README.TXT | 49 + modules/validator/validator.c | 1052 + modules/vtt_in/Makefile | 51 + modules/vtt_in/vtt_dec.c | 396 + modules/vtt_in/vtt_in.c | 445 + modules/wav_out/Makefile | 44 + modules/wav_out/wav_out.c | 495 + modules/widgetman/Makefile | 64 + modules/widgetman/unzip.c | 1379 + modules/widgetman/unzip.h | 491 + modules/widgetman/wgt_load.c | 302 + modules/widgetman/wgt_load_base.js | 84 + modules/widgetman/widget.c | 452 + modules/widgetman/widgetman.c | 3684 ++ modules/widgetman/widgetman.h | 360 + modules/wiiis/Makefile | 49 + modules/wiiis/test_wii.bt | 251 + modules/wiiis/wiiis.c | 264 + modules/x11_out/Makefile | 84 + modules/x11_out/x11_out.c | 1820 + modules/x11_out/x11_out.h | 132 + modules/xvid_dec/Makefile | 61 + modules/xvid_dec/xvid_dec.c | 515 + modules/xvid_dec/xvid_dec_wce.cpp | 303 + packagers/win32_64/nsis/default.out | 0 packagers/win32_64/nsis/gpac_installer.nsi | 964 + packagers/win32_64/nsis/readme.txt | 13 + regression_tests/_mozilla_ie_action.html | 35 + regression_tests/_mozilla_ie_simple.html | 24 + regression_tests/_ppc_action.html | 35 + regression_tests/_ppc_simple.html | 25 + .../auxiliary_files/count_arabic.mp3 | Bin 0 -> 59872 bytes .../auxiliary_files/count_english.mp3 | Bin 0 -> 60060 bytes .../auxiliary_files/count_french.mp3 | Bin 0 -> 60060 bytes .../auxiliary_files/count_german.mp3 | Bin 0 -> 57365 bytes .../auxiliary_files/count_italian.mp3 | Bin 0 -> 57678 bytes .../auxiliary_files/count_spanish.mp3 | Bin 0 -> 60186 bytes .../auxiliary_files/count_video.cmp | Bin 0 -> 146688 bytes .../auxiliary_files/enst_audio.aac | Bin 0 -> 85058 bytes .../auxiliary_files/enst_video.h264 | Bin 0 -> 47679 bytes .../auxiliary_files/index2batch.xslt | 54 + .../auxiliary_files/index2html.xslt | 62 + .../auxiliary_files/index2sh.xslt | 71 + regression_tests/auxiliary_files/logo.bt | 126 + regression_tests/auxiliary_files/logo.jpg | Bin 0 -> 13781 bytes regression_tests/auxiliary_files/logo.png | Bin 0 -> 15681 bytes .../auxiliary_files/nefertiti.wrl | 649 + regression_tests/auxiliary_files/sky.jpg | Bin 0 -> 6496 bytes regression_tests/auxiliary_files/subtitle.srt | 23 + .../auxiliary_files/subtitle_fr.srt | 23 + .../auxiliary_files/svg2html.xslt | 117 + .../auxiliary_files/x3d2html.xslt | 127 + .../auxiliary_files/xmt2html.xslt | 159 + .../bifs-2D-background-background2D-bind.bt | 71 + .../bifs-2D-background-background2D-image.bt | 97 + ...bifs-2D-background-background2D-layer2D.bt | 92 + .../bifs-2D-background-background2D-movie.bt | 94 + ...s-2D-background-background2D-url-change.bt | 105 + .../bifs/bifs-2D-interactivity-discsensor.bt | 129 + .../bifs/bifs-2D-interactivity-htk-sensor.bt | 175 + .../bifs/bifs-2D-interactivity-keysensor.bt | 810 + .../bifs/bifs-2D-interactivity-mousesensor.bt | 182 + .../bifs-2D-interactivity-nested-sensors.bt | 123 + .../bifs-2D-interactivity-planesensor2D.bt | 124 + ...bifs-2D-interactivity-proximitysensor2D.bt | 89 + .../bifs-2D-interactivity-stringsensor.bt | 153 + ...fs-2D-interactivity-touchsensor-4states.bt | 103 + ...s-2D-interactivity-touchsensor-hitpoint.bt | 91 + ...ivity-touchsensor-isactive-exposedfield.bt | 99 + ...s-2D-interactivity-touchsensor-isactive.bt | 98 + ...ifs-2D-interactivity-touchsensor-isover.bt | 59 + ...-2D-interactivity-touchsensor-move_over.bt | 268 + .../bifs-2D-painting-colortransform-alpha.bt | 101 + .../bifs-2D-painting-colortransform-bitmap.bt | 109 + .../bifs-2D-painting-colortransform-color.bt | 102 + .../bifs/bifs-2D-painting-lineproperties.bt | 168 + .../bifs/bifs-2D-painting-material2D.bt | 154 + .../bifs-2D-painting-xlineproperties-cap.bt | 211 + ...ting-xlineproperties-compositetexture2D.bt | 153 + .../bifs-2D-painting-xlineproperties-dash.bt | 142 + ...D-painting-xlineproperties-imagetexture.bt | 159 + .../bifs-2D-painting-xlineproperties-join.bt | 215 + ...painting-xlineproperties-lineargradient.bt | 122 + ...painting-xlineproperties-radialgradient.bt | 124 + ...fs-2D-painting-xlineproperties-scalable.bt | 123 + ...2D-painting-xlineproperties-transparent.bt | 176 + .../bifs/bifs-2D-positioning-clipper2D.bt | 316 + .../bifs-2D-positioning-form-align-center.bt | 162 + .../bifs-2D-positioning-form-align-horiz.bt | 129 + .../bifs-2D-positioning-form-align-vert.bt | 129 + .../bifs-2D-positioning-form-spread-horiz.bt | 182 + .../bifs-2D-positioning-form-spread-vert.bt | 170 + .../bifs/bifs-2D-positioning-layer2D.bt | 129 + .../bifs-2D-positioning-layer2d-in-layer2d.bt | 111 + ...-2D-positioning-layout-horiz-ltr-nowrap.bt | 403 + ...D-positioning-layout-horiz-ltr-wrap-btt.bt | 445 + ...D-positioning-layout-horiz-ltr-wrap-ttb.bt | 434 + ...-2D-positioning-layout-horiz-rtl-nowrap.bt | 415 + ...D-positioning-layout-horiz-rtl-wrap-btt.bt | 469 + ...D-positioning-layout-horiz-rtl-wrap-ttb.bt | 457 + .../bifs-2D-positioning-layout-horiz-text.bt | 84 + ...bifs-2D-positioning-layout-scroll-child.bt | 87 + .../bifs-2D-positioning-layout-scroll-full.bt | 344 + ...D-positioning-layout-scroll-modes-horiz.bt | 349 + ...2D-positioning-layout-scroll-modes-vert.bt | 350 + ...ifs-2D-positioning-layout-scroll-on-off.bt | 218 + ...s-2D-positioning-layout-vert-btt-nowrap.bt | 340 + ...2D-positioning-layout-vert-btt-wrap-ltr.bt | 372 + ...2D-positioning-layout-vert-btt-wrap-rtl.bt | 381 + ...s-2D-positioning-layout-vert-ttb-nowrap.bt | 331 + ...2D-positioning-layout-vert-ttb-wrap-ltr.bt | 363 + ...2D-positioning-layout-vert-ttb-wrap-rtl.bt | 372 + .../bifs/bifs-2D-positioning-orderedgroup.bt | 86 + ...bifs-2D-positioning-pathlayout-graphics.bt | 177 + .../bifs/bifs-2D-positioning-pathlayout.bt | 164 + .../bifs/bifs-2D-positioning-transform2D.bt | 133 + .../bifs-2D-positioning-transformmatrix2D.bt | 179 + regression_tests/bifs/bifs-2D-shapes-all.bt | 267 + .../bifs/bifs-2D-shapes-indexfaceset2D.bt | 123 + .../bifs/bifs-2D-shapes-indexlineset2D.bt | 100 + .../bifs/bifs-2D-shapes-pointset2D.bt | 56 + .../bifs/bifs-2D-shapes-xcurve2D.bt | 188 + ...texturing-compositetexture2D-background.bt | 117 + ...-2D-texturing-compositetexture2D-bitmap.bt | 89 + ...exturing-compositetexture2D-transparent.bt | 129 + .../bifs/bifs-2D-texturing-gradients-text.bt | 137 + ...bifs-2D-texturing-gradients-transparent.bt | 120 + .../bifs-2D-texturing-imagetexture-shapes.bt | 282 + ...bifs-2D-texturing-lineargradient-simple.bt | 75 + ...bifs-2D-texturing-lineargradient-spread.bt | 113 + .../bifs-2D-texturing-movietexture-shapes.bt | 285 + .../bifs/bifs-2D-texturing-pixeltexture.bt | 191 + ...bifs-2D-texturing-radialgradient-simple.bt | 94 + ...bifs-2D-texturing-radialgradient-spread.bt | 118 + ...bifs-2D-texturing-texturetransform-base.bt | 234 + ...-2D-texturing-texturetransform-interact.bt | 231 + ...ring-texturetransform-transformmatrix2D.bt | 242 + .../bifs/bifs-2D-viewport-complete.bt | 715 + .../bifs/bifs-2D-viewport-simple.bt | 88 + .../bifs/bifs-3D-background-images.bt | 87 + regression_tests/bifs/bifs-3D-background.bt | 56 + .../bifs-3D-interactivity-collision-proxy.bt | 80 + .../bifs/bifs-3D-interactivity-collision.bt | 79 + .../bifs-3D-interactivity-cylindersensor.bt | 90 + .../bifs/bifs-3D-interactivity-planesensor.bt | 93 + .../bifs-3D-interactivity-proximitysensor.bt | 80 + .../bifs-3D-interactivity-spheresensor.bt | 90 + .../bifs-3D-interactivity-visibilitysensor.bt | 100 + .../bifs/bifs-3D-lighting-directionalLight.bt | 63 + regression_tests/bifs/bifs-3D-lighting-fog.bt | 56 + .../bifs/bifs-3D-lighting-pointlight.bt | 71 + .../bifs/bifs-3D-lighting-spotlight.bt | 72 + ...-positioning-billboard-viewer-alignment.bt | 62 + .../bifs/bifs-3D-positioning-billboard.bt | 61 + .../bifs/bifs-3D-positioning-gravity.bt | 71 + .../bifs/bifs-3D-positioning-layer3D-views.bt | 160 + .../bifs/bifs-3D-positioning-layer3D.bt | 186 + .../bifs/bifs-3D-positioning-lod.bt | 63 + .../bifs/bifs-3D-positioning-transform.bt | 64 + .../bifs/bifs-3D-shapes-box-transparent.bt | 118 + regression_tests/bifs/bifs-3D-shapes-box.bt | 45 + regression_tests/bifs/bifs-3D-shapes-cone.bt | 58 + .../bifs/bifs-3D-shapes-cylinder.bt | 92 + .../bifs/bifs-3D-shapes-elevationgrid.bt | 74 + .../bifs/bifs-3D-shapes-extrusion.bt | 99 + .../bifs/bifs-3D-shapes-indexedfaceset.bt | 66 + .../bifs/bifs-3D-shapes-indexedlineset.bt | 99 + .../bifs/bifs-3D-shapes-nonlineardeformer.bt | 796 + .../bifs/bifs-3D-shapes-pointset.bt | 46 + .../bifs/bifs-3D-texturing-box-transparent.bt | 73 + .../bifs/bifs-3D-texturing-box-video.bt | 184 + .../bifs/bifs-3D-texturing-box.bt | 69 + ...-3D-texturing-compositetexture3D-bitmap.bt | 113 + ...ifs-3D-texturing-compositetexture3D-box.bt | 106 + .../bifs-3D-texturing-cone-transparent.bt | 68 + .../bifs/bifs-3D-texturing-cone.bt | 81 + .../bifs-3D-texturing-cylinder-transparent.bt | 93 + .../bifs/bifs-3D-texturing-cylinder.bt | 107 + .../bifs/bifs-3D-texturing-transform-box.bt | 85 + .../bifs-3D-texturing-transform-matrix-box.bt | 91 + .../bifs/bifs-3D-viewpoint-anim.bt | 84 + .../bifs/bifs-3D-viewpoint-bind-jump.bt | 114 + .../bifs/bifs-3D-viewpoint-bind.bt | 115 + .../bifs/bifs-3D-viewpoint-ortho-bind.bt | 114 + .../bifs/bifs-bitmap-image-meter-metrics.bt | 80 + .../bifs/bifs-bitmap-image-pixel-metrics.bt | 89 + .../bifs/bifs-bitmap-image-resizing.bt | 153 + .../bifs/bifs-bitmap-movie-materialkey.bt | 101 + regression_tests/bifs/bifs-bitmap-movie.bt | 84 + .../bifs/bifs-bitmap-video-resizing.bt | 152 + .../bifs/bifs-cachetexture_cache.bt | 90 + .../bifs/bifs-cachetexture_nocache.bt | 57 + .../bifs/bifs-command-animated-osmo4logo.bt | 315 + .../bifs/bifs-command-delete-index.bt | 58 + .../bifs/bifs-command-delete-node.bt | 58 + .../bifs/bifs-command-delete-route.bt | 67 + .../bifs/bifs-command-global-qp.bt | 66 + .../bifs/bifs-command-insert-index.bt | 58 + .../bifs/bifs-command-insert-node.bt | 74 + .../bifs/bifs-command-insert-nodedef.bt | 64 + .../bifs/bifs-command-insert-route.bt | 67 + .../bifs-command-multiple-replace-field.bt | 66 + .../bifs-command-multiple-replace-index.bt | 62 + .../bifs/bifs-command-node-delete-ex.bt | 125 + .../bifs/bifs-command-proto-delete.bt | 93 + .../bifs/bifs-command-proto-insert.bt | 83 + .../bifs/bifs-command-protolist-delete.bt | 93 + .../bifs/bifs-command-quantification.bt | 186 + .../bifs/bifs-command-replace-field.bt | 67 + .../bifs/bifs-command-replace-index.bt | 58 + .../bifs/bifs-command-replace-node-null.bt | 65 + .../bifs/bifs-command-replace-node.bt | 67 + .../bifs/bifs-command-replace-route.bt | 67 + .../bifs/bifs-command-replace-scene-null.bt | 37 + .../bifs/bifs-command-replace-scene.bt | 76 + .../bifs/bifs-command-route-add-children.bt | 79 + .../bifs/bifs-command-route-children.bt | 79 + .../bifs-command-route-node-exposedfield.bt | 80 + .../bifs/bifs-command-route-node.bt | 76 + .../bifs-command-route-remove-children.bt | 93 + regression_tests/bifs/bifs-environmenttest.bt | 129 + .../bifs/bifs-externproto-forestgump-lib.bt | 463 + .../bifs/bifs-externproto-forestgump.bt | 96 + .../bifs/bifs-externproto-mfurl-lib.bt | 52 + .../bifs/bifs-externproto-mfurl.bt | 69 + .../bifs/bifs-externproto-nood-lib.bt | 109 + .../bifs/bifs-externproto-nood.bt | 70 + .../bifs/bifs-externproto-simple-lib.bt | 90 + .../bifs/bifs-externproto-simple.bt | 81 + regression_tests/bifs/bifs-game-arrange.bt | 452 + regression_tests/bifs/bifs-game-breakout.bt | 1035 + regression_tests/bifs/bifs-game-bubble.bt | 433 + .../bifs/bifs-game-minesweeper.bt | 1538 + regression_tests/bifs/bifs-game-othello.bt | 2836 + .../bifs-interpolation-colorinterpolator.bt | 63 + ...-interpolation-coordinateinterpolator2D.bt | 64 + .../bifs-interpolation-positionanimator.bt | 63 + .../bifs-interpolation-positionanimator2D.bt | 65 + ...rpolation-positioninterpolator-position.bt | 94 + ...interpolation-positioninterpolator-size.bt | 58 + ...olation-positioninterpolator2D-position.bt | 96 + ...terpolation-positioninterpolator2D-size.bt | 64 + .../bifs/bifs-interpolation-scalaranimator.bt | 66 + .../bifs-interpolation-scalarinterpolator.bt | 63 + .../bifs-interpolation-timesensor-enabled.bt | 82 + ...polation-timesensor-starttime_norestart.bt | 81 + ...erpolation-timesensor-starttime_restart.bt | 82 + .../bifs-interpolation-valuator-sftime.bt | 58 + regression_tests/bifs/bifs-keynavigator.bt | 220 + .../bifs/bifs-linking-anchor-mp4-next.bt | 67 + .../bifs/bifs-linking-anchor-mp4-prev.bt | 67 + .../bifs/bifs-linking-anchor-viewpoint.bt | 92 + .../bifs/bifs-linking-anchor-www.bt | 67 + .../bifs/bifs-linking-animationstream.bt | 135 + .../bifs/bifs-linking-inline-direct-inline.bt | 75 + .../bifs/bifs-linking-inline-direct.bt | 51 + .../bifs/bifs-linking-inline-od-inline.bt | 76 + .../bifs/bifs-linking-inline-od.bt | 60 + .../bifs/bifs-linking-inline-rtsp-no-od.bt | 48 + .../bifs/bifs-linking-inline-rtsp.bt | 59 + .../bifs-linking-inline-segment-inline.bt | 74 + .../bifs/bifs-linking-inline-segment.bt | 41 + .../bifs/bifs-media-audiobuffer.bt | 203 + .../bifs/bifs-media-audioclip-urlchanged.bt | 145 + regression_tests/bifs/bifs-media-audioclip.bt | 133 + .../bifs/bifs-media-audiosource-mixing.bt | 194 + .../bifs/bifs-media-audiosource-urlchanged.bt | 146 + .../bifs/bifs-media-audiosource.bt | 133 + .../bifs/bifs-media-imagetexture-OD-reuse.bt | 89 + .../bifs/bifs-media-imagetexture-no-od.bt | 60 + .../bifs-media-imagetexture-object-scale.bt | 97 + .../bifs-media-imagetexture-transparent.bt | 275 + .../bifs-media-imagetexture-url-change.bt | 95 + .../bifs/bifs-media-movietexture-control.bt | 148 + .../bifs/bifs-media-movietexture-no-od.bt | 65 + .../bifs-media-movietexture-od-joinsession.bt | 93 + ...ifs-media-movietexture-od-leave-session.bt | 93 + .../bifs/bifs-media-movietexture-owns-OCR.bt | 75 + .../bifs-media-movietexture-shares-OCR.bt | 74 + .../bifs-media-movietexture-url-change.bt | 158 + .../bifs/bifs-media-sound-spatialize.bt | 77 + regression_tests/bifs/bifs-media-sound.bt | 77 + .../bifs/bifs-misc-UTF16-input.bt | 55 + .../bifs/bifs-misc-cyclic-graph.bt | 55 + .../bifs/bifs-misc-hc-proto-events.bt | 57 + .../bifs/bifs-misc-hc-proto-pathextrusion.bt | 103 + .../bifs-misc-hc-proto-planarextrusion.bt | 87 + .../bifs/bifs-misc-hc-proto-planeclipper.bt | 69 + ...ifs-misc-non-linear-parsing-conditional.bt | 69 + .../bifs/bifs-misc-non-linear-parsing-use.bt | 60 + ...-misc-srt-import-3gpp-control-share-ocr.bt | 64 + .../bifs/bifs-misc-srt-import-3gpp-control.bt | 64 + .../bifs/bifs-misc-srt-import-3gpp.bt | 64 + regression_tests/bifs/bifs-misc-srt-import.bt | 76 + regression_tests/bifs/bifs-od-remove-esd.bt | 78 + regression_tests/bifs/bifs-od-remove-od.bt | 78 + regression_tests/bifs/bifs-od-update-od.bt | 89 + .../bifs/bifs-proto-conditional.bt | 107 + .../bifs/bifs-proto-delete-def.bt | 91 + .../bifs/bifs-proto-delete-index.bt | 95 + .../bifs/bifs-proto-forestgump.bt | 478 + regression_tests/bifs/bifs-proto-mfurl.bt | 78 + regression_tests/bifs/bifs-proto-multiple.bt | 180 + regression_tests/bifs/bifs-proto-nested.bt | 132 + regression_tests/bifs/bifs-proto-route.bt | 110 + .../bifs/bifs-proto-sftime-protocode.bt | 99 + .../bifs/bifs-proto-sftime-protointerface.bt | 104 + regression_tests/bifs/bifs-proto-simple.bt | 88 + regression_tests/bifs/bifs-proto-use.bt | 93 + .../bifs/bifs-script-char-to-int.bt | 87 + .../bifs/bifs-script-child-create.bt | 61 + regression_tests/bifs/bifs-script-date.bt | 64 + .../bifs/bifs-script-event-out.bt | 85 + .../bifs/bifs-script-initialize.bt | 86 + regression_tests/bifs/bifs-script-load-url.bt | 67 + .../bifs/bifs-script-node-access.bt | 86 + .../bifs/bifs-script-node-create.bt | 80 + regression_tests/bifs/bifs-script-proto.bt | 223 + .../bifs/bifs-script-timestamp.bt | 68 + regression_tests/bifs/bifs-storage.bt | 65 + .../bifs/bifs-stream-text-switch.bt | 143 + .../bifs/bifs-text-align-horiz1.bt | 304 + .../bifs/bifs-text-align-horiz2.bt | 320 + .../bifs/bifs-text-align-horiz3.bt | 320 + .../bifs/bifs-text-align-horiz4.bt | 336 + .../bifs/bifs-text-align-vert1.bt | 200 + .../bifs/bifs-text-align-vert2.bt | 209 + .../bifs/bifs-text-align-vert3.bt | 209 + .../bifs/bifs-text-align-vert4.bt | 218 + .../bifs/bifs-text-glyph-advance.bt | 436 + regression_tests/bifs/bifs-text-length.bt | 230 + regression_tests/bifs/bifs-text-maxextend.bt | 176 + regression_tests/bifs/bifs-text-style.bt | 184 + regression_tests/bifs/bifs-text-unicode.bt | 55 + .../bifs/bifs-text-vrml-alignment.bt | 161 + .../bifs/bifs-timeline-mediacontrol-OCR.bt | 245 + .../bifs-timeline-mediacontrol-audio-speed.bt | 214 + .../bifs/bifs-timeline-mediacontrol-audio.bt | 352 + .../bifs-timeline-mediacontrol-complete.bt | 266 + ...bifs-timeline-mediacontrol-deactivation.bt | 105 + .../bifs-timeline-mediacontrol-inline-av.bt | 96 + ...s-timeline-mediacontrol-inline-segments.bt | 66 + .../bifs/bifs-timeline-mediacontrol-inline.bt | 231 + .../bifs/bifs-timeline-mediacontrol-rtsp.bt | 340 + .../bifs-timeline-mediacontrol-seg-inline.bt | 81 + .../bifs-timeline-mediacontrol-segments.bt | 154 + .../bifs/bifs-timeline-mediacontrol-video.bt | 258 + .../bifs-timeline-mediacontrol-videospeed.bt | 202 + ...ifs-timeline-mediasensor-segment-switch.bt | 226 + .../bifs/bifs-timeline-mediasensor-segment.bt | 215 + .../bifs/bifs-timeline-mediasensor.bt | 137 + regression_tests/build-navigator-sh | 11 + regression_tests/build-navigator-w32.bat | 14 + regression_tests/build-shell | 49 + regression_tests/build-w32.bat | 54 + regression_tests/dom/gpac-dom-portability.js | 144 + regression_tests/dom/gpac-html-portability.js | 96 + .../html5_video/basic_arraybuffer.js | 21 + regression_tests/html5_video/basic_audio.svg | 12 + .../html5_video/basic_mediasource.js | 25 + .../html5_video/basic_sourcebuffer.js | 53 + regression_tests/html5_video/basic_url.js | 26 + regression_tests/html5_video/basic_video.js | 81 + regression_tests/html5_video/basic_video.svg | 7 + regression_tests/html5_video/bind.js | 26 + .../counter-mp4-audio-segments-http.js | 20 + .../counter-mp4-av-segments-http.js | 20 + .../counter-mp4-video-segments-http.js | 36 + ...unter-mp4-video-segments-live-nobs-http.js | 36 + .../counter-mp4-video-segments-local.js | 28 + regression_tests/html5_video/file.json | 1 + regression_tests/html5_video/file.txt | 1 + regression_tests/html5_video/file.xml | 4 + .../html5_video/gpac-mse-spatial.js | 55 + regression_tests/html5_video/gpac-mse.js | 358 + .../html5_video/implementation_notes.txt | 36 + regression_tests/html5_video/mediaevents.js | 348 + regression_tests/html5_video/mediaevents.svg | 29 + regression_tests/html5_video/mse-overlap.js | 71 + regression_tests/html5_video/mse.svg | 58 + regression_tests/html5_video/myanmar-tiles.js | 135 + .../html5_video/nodejs-byte-server.js | 71 + .../redbull-mp4-audio-segments-http.js | 36 + .../redbull-mp4-video-segments-http.js | 140 + regression_tests/html5_video/spatial-mse.svg | 28 + regression_tests/html5_video/two-videos.svg | 33 + regression_tests/html5_video/video.svg | 30 + regression_tests/html5_video/xhr.js | 147 + regression_tests/html5_video/xhr.svg | 4 + regression_tests/index.css | 134 + regression_tests/index.xml | 373 + regression_tests/svg/all_syntaxes_1.1F2.svg | 498 + regression_tests/svg/createanim-by-script.svg | 73 + .../svg/createimage-by-script.svg | 16 + regression_tests/svg/utfscript.svg | 14 + regression_tests/ttml/ebu-ttd_sample.ttml | 39 + .../ttml/ebu-ttd_sample_invalid_ns.ttml | 28 + .../ttml/ebu-ttd_sample_span.ttml | 29 + .../ttml/ebu-ttd_timing_contiguous.ttml | 30 + .../ttml/ebu-ttd_timing_non-contiguous.ttml | 30 + .../ttml/ebu-ttd_timing_overlapping_fail.ttml | 29 + regression_tests/utfscript.svg | 14 + regression_tests/webvtt/comments.vtt | 45 + regression_tests/webvtt/concatenation.vtt | 51 + regression_tests/webvtt/counter.srt | 2400 + regression_tests/webvtt/counter.vtt | 4502 ++ .../webvtt/elephants-dream-chapters-en.vtt | 29 + .../webvtt/elephants-dream-subtitles-de.vtt | 309 + .../webvtt/elephants-dream-subtitles-en.vtt | 357 + regression_tests/webvtt/empty.vtt | 1 + regression_tests/webvtt/empty2.vtt | 1 + regression_tests/webvtt/empty3.vtt | 2 + regression_tests/webvtt/empty4.vtt | 3 + regression_tests/webvtt/header.vtt | 42 + regression_tests/webvtt/invalid1.vtt | 3 + regression_tests/webvtt/invalid2.vtt | 3 + regression_tests/webvtt/invalid3.vtt | 5 + regression_tests/webvtt/invalid4.vtt | 8 + regression_tests/webvtt/invalid5.vtt | 12 + regression_tests/webvtt/long-duration.vtt | 43814 ++++++++++++++++ .../webvtt/multiline-header-additional.vtt | 23 + .../webvtt/multiline-header-id-invalid.vtt | 23 + .../webvtt/multiline-header-id.vtt | 22 + regression_tests/webvtt/multiline-header.vtt | 25 + regression_tests/webvtt/overlapping-end.vtt | 17 + .../webvtt/overlapping-middle.vtt | 17 + .../webvtt/overlapping-rewritten.vtt | 81 + regression_tests/webvtt/overlapping-start.vtt | 17 + regression_tests/webvtt/overlapping.vtt | 26 + regression_tests/webvtt/simple.vtt | 32 + regression_tests/webvtt/spaces.vtt | 36 + .../webvtt/spec-example-basic.vtt | 40 + .../webvtt/spec-example-comment.vtt | 10 + .../webvtt/spec-example-comment2.vtt | 21 + .../webvtt/spec-example-identifier.vtt | 8 + .../webvtt/spec-example-multiple-lines.vtt | 11 + .../webvtt/spec-example-nested.vtt | 19 + .../webvtt/spec-example-voice.vtt | 13 + regression_tests/webvtt/svg.vtt | 4502 ++ .../webvtt/timestamps-invalid.vtt | 10 + regression_tests/webvtt/timestamps.vtt | 19 + regression_tests/x3d/x3d-2D-Arc2d.x3dv | 23 + regression_tests/x3d/x3d-2D-ArcClose2d.x3dv | 24 + regression_tests/x3d/x3d-2D-Disk2d.x3dv | 24 + regression_tests/x3d/x3d-2D-Polyline2d.x3dv | 23 + regression_tests/x3d/x3d-2D-Polypoint2d.x3dv | 23 + .../x3d/x3d-2D-TriangleSet2d.x3dv | 24 + .../x3d/x3d-3D-IndexedTriangleFanSet.x3dv | 28 + .../x3d/x3d-3D-IndexedTriangleSet.x3dv | 27 + .../x3d/x3d-3D-IndexedTriangleStripSet.x3dv | 28 + regression_tests/x3d/x3d-3D-LineSet.x3dv | 27 + .../x3d/x3d-3D-TriangleFanSet.x3dv | 28 + regression_tests/x3d/x3d-3D-TriangleSet.x3dv | 26 + .../x3d/x3d-3D-TriangleStripSet.x3dv | 28 + regression_tests/x3d/x3d-misc-ColorRGBA.x3dv | 42 + regression_tests/x3d/x3d-misc-HatchStyle.x3dv | 31 + regression_tests/x3d/x3d-misc-KeySensor.x3dv | 73 + .../x3d/x3d-misc-StringSensor.x3dv | 83 + regression_tests/xmlin4/ebu-ttd_sample.ttml | 39 + regression_tests/xmlin4/first.xml | 3 + regression_tests/xmlin4/input.txt | 13 + regression_tests/xmlin4/input.xml | 5 + regression_tests/xmlin4/last.xml | 3 + .../xmlin4/meta-mett-no-mime.nhml | 8 + .../xmlin4/meta-mett-xml-header.nhml | 6 + regression_tests/xmlin4/meta-mett-xml.nhml | 6 + regression_tests/xmlin4/meta-mett.nhml | 8 + .../xmlin4/meta-metx-no-namespace.nhml | 6 + regression_tests/xmlin4/meta-metx.nhml | 6 + regression_tests/xmlin4/run_one_test.sh | 21 + regression_tests/xmlin4/run_tests.sh | 59 + regression_tests/xmlin4/second.xml | 3 + .../xmlin4/subt-sbtt-no-mime.nhml | 6 + regression_tests/xmlin4/subt-sbtt.nhml | 6 + .../xmlin4/subt-stpp-no-namespace.nhml | 6 + regression_tests/xmlin4/subt-stpp.nhml | 6 + regression_tests/xmlin4/text-stxt-header.nhml | 7 + .../xmlin4/text-stxt-no-mime.nhml | 8 + regression_tests/xmlin4/text-stxt.nhml | 8 + run_configure.sh | 21 + src/Makefile | 656 + src/bifs/arith_decoder.c | 286 + src/bifs/bifs_codec.c | 534 + src/bifs/bifs_node_tables.c | 1153 + src/bifs/com_dec.c | 1382 + src/bifs/com_enc.c | 981 + src/bifs/conditional.c | 194 + src/bifs/field_decode.c | 938 + src/bifs/field_encode.c | 668 + src/bifs/memory_decoder.c | 1040 + src/bifs/predictive_mffield.c | 451 + src/bifs/quant.h | 122 + src/bifs/quantize.c | 338 + src/bifs/script.h | 112 + src/bifs/script_dec.c | 786 + src/bifs/script_enc.c | 1833 + src/bifs/unquantize.c | 441 + src/compositor/audio_input.c | 449 + src/compositor/audio_mixer.c | 805 + src/compositor/audio_render.c | 757 + src/compositor/bindable.c | 326 + src/compositor/camera.c | 604 + src/compositor/compositor.c | 3494 ++ src/compositor/compositor_2d.c | 1693 + src/compositor/compositor_3d.c | 263 + src/compositor/compositor_node_init.c | 654 + src/compositor/drawable.c | 1538 + src/compositor/drawable.h | 327 + src/compositor/events.c | 2072 + src/compositor/font_engine.c | 1508 + src/compositor/gl_inc.h | 490 + src/compositor/hardcoded_protos.c | 1235 + src/compositor/hc_flash_shape.c | 471 + src/compositor/mesh.c | 2334 + src/compositor/mesh_collide.c | 609 + src/compositor/mesh_tesselate.c | 497 + src/compositor/mpeg4_animstream.c | 201 + src/compositor/mpeg4_audio.c | 611 + src/compositor/mpeg4_background.c | 573 + src/compositor/mpeg4_background2d.c | 490 + src/compositor/mpeg4_bitmap.c | 277 + src/compositor/mpeg4_composite.c | 871 + src/compositor/mpeg4_form.c | 680 + src/compositor/mpeg4_geometry_2d.c | 724 + src/compositor/mpeg4_geometry_3d.c | 530 + src/compositor/mpeg4_geometry_ifs2d.c | 345 + src/compositor/mpeg4_geometry_ils2d.c | 314 + src/compositor/mpeg4_gradients.c | 638 + src/compositor/mpeg4_grouping.c | 826 + src/compositor/mpeg4_grouping.h | 196 + src/compositor/mpeg4_grouping_2d.c | 421 + src/compositor/mpeg4_grouping_3d.c | 407 + src/compositor/mpeg4_layer_2d.c | 389 + src/compositor/mpeg4_layer_3d.c | 702 + src/compositor/mpeg4_layout.c | 844 + src/compositor/mpeg4_lighting.c | 175 + src/compositor/mpeg4_path_layout.c | 281 + src/compositor/mpeg4_sensors.c | 1606 + src/compositor/mpeg4_sound.c | 287 + src/compositor/mpeg4_text.c | 764 + src/compositor/mpeg4_textures.c | 612 + src/compositor/mpeg4_timesensor.c | 207 + src/compositor/mpeg4_viewport.c | 613 + src/compositor/navigate.c | 765 + src/compositor/nodes_stacks.h | 337 + src/compositor/offscreen_cache.c | 863 + src/compositor/offscreen_cache.h | 59 + src/compositor/svg_base.c | 384 + src/compositor/svg_filters.c | 443 + src/compositor/svg_font.c | 547 + src/compositor/svg_geometry.c | 705 + src/compositor/svg_grouping.c | 1398 + src/compositor/svg_media.c | 908 + src/compositor/svg_paint_servers.c | 798 + src/compositor/svg_text.c | 1525 + src/compositor/texturing.c | 344 + src/compositor/texturing.h | 102 + src/compositor/texturing_gl.c | 1754 + src/compositor/visual_manager.c | 300 + src/compositor/visual_manager.h | 264 + src/compositor/visual_manager_2d.c | 913 + src/compositor/visual_manager_2d.h | 147 + src/compositor/visual_manager_2d_draw.c | 821 + src/compositor/visual_manager_3d.c | 2054 + src/compositor/visual_manager_3d.h | 318 + src/compositor/visual_manager_3d_gl.c | 2987 ++ src/compositor/x3d_geometry.c | 1055 + src/dir_info | 47 + src/export.cpp | 2102 + src/ietf/rtcp.c | 601 + src/ietf/rtp.c | 983 + src/ietf/rtp_depacketizer.c | 1781 + src/ietf/rtp_packetizer.c | 613 + src/ietf/rtp_pck_3gpp.c | 778 + src/ietf/rtp_pck_mpeg12.c | 241 + src/ietf/rtp_pck_mpeg4.c | 782 + src/ietf/rtp_streamer.c | 849 + src/ietf/rtsp_command.c | 571 + src/ietf/rtsp_common.c | 390 + src/ietf/rtsp_response.c | 721 + src/ietf/rtsp_session.c | 778 + src/ietf/sdp.c | 1162 + src/isomedia/avc_ext.c | 1956 + src/isomedia/box_code_3gpp.c | 1288 + src/isomedia/box_code_adobe.c | 696 + src/isomedia/box_code_apple.c | 326 + src/isomedia/box_code_base.c | 9128 ++++ src/isomedia/box_code_drm.c | 1890 + src/isomedia/box_code_meta.c | 735 + src/isomedia/box_dump.c | 4646 ++ src/isomedia/box_funcs.c | 2970 ++ src/isomedia/data_map.c | 677 + src/isomedia/drm_sample.c | 1319 + src/isomedia/hint_track.c | 994 + src/isomedia/hinting.c | 995 + src/isomedia/isom_intern.c | 994 + src/isomedia/isom_read.c | 3772 ++ src/isomedia/isom_store.c | 1332 + src/isomedia/isom_write.c | 5178 ++ src/isomedia/media.c | 936 + src/isomedia/media_odf.c | 522 + src/isomedia/meta.c | 697 + src/isomedia/movie_fragments.c | 2163 + src/isomedia/sample_descs.c | 1098 + src/isomedia/stbl_read.c | 614 + src/isomedia/stbl_write.c | 1791 + src/isomedia/track.c | 1197 + src/isomedia/ttml.c | 134 + src/isomedia/tx3g.c | 735 + src/laser/lsr_dec.c | 5629 ++ src/laser/lsr_enc.c | 4390 ++ src/laser/lsr_tables.c | 1252 + src/mcrypt/cbc.c | 173 + src/mcrypt/cfb.c | 160 + src/mcrypt/ctr.c | 237 + src/mcrypt/des.c | 588 + src/mcrypt/ecb.c | 88 + src/mcrypt/g_crypt.c | 391 + src/mcrypt/ncfb.c | 320 + src/mcrypt/nofb.c | 211 + src/mcrypt/ofb.c | 163 + src/mcrypt/rijndael-128.c | 417 + src/mcrypt/rijndael-192.c | 418 + src/mcrypt/rijndael-256.c | 416 + src/mcrypt/stream.c | 75 + src/mcrypt/tripledes.c | 767 + src/media_tools/ait.c | 792 + src/media_tools/av_parsers.c | 4965 ++ src/media_tools/avilib.c | 3115 ++ src/media_tools/dash_client.c | 5828 ++ src/media_tools/dash_segmenter.c | 5852 +++ src/media_tools/dsmcc.c | 1939 + src/media_tools/dvb_mpe.c | 1330 + src/media_tools/filestreamer.c | 647 + src/media_tools/gpac_ogg.c | 1330 + src/media_tools/html5_media.c | 421 + src/media_tools/html5_mse.c | 1060 + src/media_tools/img.c | 755 + src/media_tools/ismacryp.c | 2016 + src/media_tools/isom_hinter.c | 1233 + src/media_tools/isom_tools.c | 2870 + src/media_tools/m2ts_mux.c | 2709 + src/media_tools/m3u8.c | 1058 + src/media_tools/media_export.c | 3009 ++ src/media_tools/media_import.c | 9364 ++++ src/media_tools/mpd.c | 2512 + src/media_tools/mpeg2_ps.c | 1795 + src/media_tools/mpeg2_ps.h | 211 + src/media_tools/mpegts.c | 4637 ++ src/media_tools/reedsolomon.c | 576 + src/media_tools/saf.c | 334 + src/media_tools/text_import.c | 2585 + src/media_tools/vobsub.c | 665 + src/media_tools/webvtt.c | 1453 + src/odf/desc_private.c | 706 + src/odf/descriptors.c | 1246 + src/odf/ipmpx_code.c | 2160 + src/odf/ipmpx_dump.c | 895 + src/odf/ipmpx_parse.c | 724 + src/odf/oci_codec.c | 427 + src/odf/odf_code.c | 3341 ++ src/odf/odf_codec.c | 611 + src/odf/odf_command.c | 653 + src/odf/odf_dump.c | 1986 + src/odf/odf_parse.c | 814 + src/odf/qos.c | 438 + src/odf/slc.c | 450 + src/scene_manager/encode_isom.c | 1375 + src/scene_manager/loader_bt.c | 3767 ++ src/scene_manager/loader_isom.c | 410 + src/scene_manager/loader_qt.c | 183 + src/scene_manager/loader_svg.c | 2106 + src/scene_manager/loader_xmt.c | 3165 ++ src/scene_manager/scene_dump.c | 3609 ++ src/scene_manager/scene_engine.c | 1116 + src/scene_manager/scene_manager.c | 811 + src/scene_manager/scene_stats.c | 633 + src/scene_manager/swf_bifs.c | 2255 + src/scene_manager/swf_parse.c | 2647 + src/scene_manager/swf_svg.c | 559 + src/scene_manager/text_to_bifs.c | 539 + src/scenegraph/base_scenegraph.c | 2381 + src/scenegraph/commands.c | 992 + src/scenegraph/dom_events.c | 944 + src/scenegraph/dom_smjs.c | 4912 ++ src/scenegraph/html5_media_smjs.c | 1720 + src/scenegraph/html5_mse_smjs.c | 949 + src/scenegraph/mpeg4_animators.c | 815 + src/scenegraph/mpeg4_nodes.c | 40409 ++++++++++++++ src/scenegraph/mpeg4_valuator.c | 511 + src/scenegraph/smil_anim.c | 1543 + src/scenegraph/smil_timing.c | 1056 + src/scenegraph/svg_attributes.c | 6464 +++ src/scenegraph/svg_properties.c | 1423 + src/scenegraph/svg_smjs.c | 2957 ++ src/scenegraph/svg_types.c | 502 + src/scenegraph/vrml_interpolators.c | 719 + src/scenegraph/vrml_proto.c | 1331 + src/scenegraph/vrml_route.c | 501 + src/scenegraph/vrml_script.c | 300 + src/scenegraph/vrml_smjs.c | 5101 ++ src/scenegraph/vrml_tools.c | 1835 + src/scenegraph/webvtt_smjs.c | 128 + src/scenegraph/x3d_nodes.c | 16429 ++++++ src/scenegraph/xbl_process.c | 238 + src/scenegraph/xml_ns.c | 1157 + src/terminal/channel.c | 1892 + src/terminal/clock.c | 351 + src/terminal/decoder.c | 1878 + src/terminal/input_sensor.c | 982 + src/terminal/input_sensor.h | 111 + src/terminal/media_control.c | 703 + src/terminal/media_control.h | 115 + src/terminal/media_manager.c | 744 + src/terminal/media_memory.c | 728 + src/terminal/media_memory.h | 189 + src/terminal/media_object.c | 1408 + src/terminal/media_sensor.c | 283 + src/terminal/mpeg4_inline.c | 767 + src/terminal/network_service.c | 1414 + src/terminal/object_browser.c | 486 + src/terminal/object_manager.c | 2315 + src/terminal/scene.c | 2522 + src/terminal/svg_external.c | 230 + src/terminal/term_node_init.c | 357 + src/terminal/terminal.c | 2489 + src/utils/alloc.c | 773 + src/utils/base_encoding.c | 280 + src/utils/bitstream.c | 1091 + src/utils/cache.c | 973 + src/utils/color.c | 1870 + src/utils/configfile.c | 502 + src/utils/dlmalloc.c | 5713 ++ src/utils/downloader.c | 3579 ++ src/utils/error.c | 1263 + src/utils/gzio.cpp | 1006 + src/utils/list.c | 836 + src/utils/map.c | 337 + src/utils/math.c | 2571 + src/utils/module.c | 520 + src/utils/module_wrap.h | 95 + src/utils/os_config_init.c | 665 + src/utils/os_divers.c | 1968 + src/utils/os_file.c | 681 + src/utils/os_module.c | 307 + src/utils/os_net.c | 1592 + src/utils/os_thread.c | 775 + src/utils/path2d.c | 1375 + src/utils/path2d_stroker.c | 1784 + src/utils/ringbuffer.c | 159 + src/utils/sha1.c | 752 + src/utils/symbian_net.cpp | 1322 + src/utils/symbian_os.cpp | 834 + src/utils/token.c | 136 + src/utils/uni_bidi.c | 1491 + src/utils/unicode.c | 107 + src/utils/url.c | 365 + src/utils/utf.c | 581 + src/utils/xml_parser.c | 2156 + src/utils/zlib_symbian_ext.h | 207 + src/utils/zutil.c | 346 + src/utils/zutil.h | 277 + version.bat | 24 + 1369 files changed, 760527 insertions(+) create mode 100644 .gitattributes create mode 100644 .travis.yml create mode 100644 AUTHORS create mode 100644 BUGS create mode 100644 COPYING create mode 100644 Changelog create mode 100644 Clean.bat create mode 100644 INSTALLME create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 applications/Makefile create mode 100644 applications/dashcast/Makefile create mode 100644 applications/dashcast/audio_data.c create mode 100644 applications/dashcast/audio_data.h create mode 100644 applications/dashcast/audio_decoder.c create mode 100644 applications/dashcast/audio_decoder.h create mode 100644 applications/dashcast/audio_encoder.c create mode 100644 applications/dashcast/audio_encoder.h create mode 100644 applications/dashcast/audio_muxer.c create mode 100644 applications/dashcast/audio_muxer.h create mode 100644 applications/dashcast/circular_buffer.c create mode 100644 applications/dashcast/circular_buffer.h create mode 100644 applications/dashcast/cmd_data.c create mode 100644 applications/dashcast/cmd_data.h create mode 100644 applications/dashcast/controler.c create mode 100644 applications/dashcast/controler.h create mode 100644 applications/dashcast/dashcast.c create mode 100644 applications/dashcast/libav_compat.h create mode 100644 applications/dashcast/message_queue.c create mode 100644 applications/dashcast/message_queue.h create mode 100644 applications/dashcast/register.c create mode 100644 applications/dashcast/register.h create mode 100644 applications/dashcast/task.c create mode 100644 applications/dashcast/task.h create mode 100644 applications/dashcast/video_data.c create mode 100644 applications/dashcast/video_data.h create mode 100644 applications/dashcast/video_decoder.c create mode 100644 applications/dashcast/video_decoder.h create mode 100644 applications/dashcast/video_encoder.c create mode 100644 applications/dashcast/video_encoder.h create mode 100644 applications/dashcast/video_muxer.c create mode 100644 applications/dashcast/video_muxer.h create mode 100644 applications/dashcast/video_scaler.c create mode 100644 applications/dashcast/video_scaler.h create mode 100644 applications/generators/MPEG4/MPEG4Gen.dsp create mode 100644 applications/generators/MPEG4/MPEG4Gen.dsw create mode 100644 applications/generators/MPEG4/Makefile create mode 100644 applications/generators/MPEG4/main.c create mode 100644 applications/generators/MPEG4/skip.txt create mode 100644 applications/generators/MPEG4/templates1.txt create mode 100644 applications/generators/MPEG4/templates10.txt create mode 100644 applications/generators/MPEG4/templates2.txt create mode 100644 applications/generators/MPEG4/templates3.txt create mode 100644 applications/generators/MPEG4/templates4.txt create mode 100644 applications/generators/MPEG4/templates5.txt create mode 100644 applications/generators/MPEG4/templates6.txt create mode 100644 applications/generators/MPEG4/templates7.txt create mode 100644 applications/generators/MPEG4/templates8.txt create mode 100644 applications/generators/MPEG4/templates9.txt create mode 100644 applications/generators/Makefile create mode 100644 applications/generators/SVG/Makefile create mode 100644 applications/generators/SVG/SVGGen.dsp create mode 100644 applications/generators/SVG/SVGGen.dsw create mode 100644 applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.nvdl create mode 100644 applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/animate.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/animation-element.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/audio.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/conditional.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/contenttype-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/coordinate-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/core-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/datatypes.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/discard.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/extensibility.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/extresources-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/flowable-text-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/focus-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/font-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/gradient-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/graphics-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/handler.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/headers.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/hyperlink.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/image.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/laser-ext.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/media-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/opacity-attrib-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/paint-attrib-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/prefetch.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/script.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/shapes.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/solidcolor.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/structure-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/text-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/transform-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/vectoreffects-attrib-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/video.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/viewport-attrib-tiny.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/xlink-attrib.rng create mode 100644 applications/generators/SVG/Tiny-1.2-NG/xml-events.rng create mode 100644 applications/generators/SVG/html.c create mode 100644 applications/generators/SVG/laser.c create mode 100644 applications/generators/SVG/main.c create mode 100644 applications/generators/SVG/svggen.h create mode 100644 applications/generators/SVG/v1.c create mode 100644 applications/generators/SVG/v2.c create mode 100644 applications/generators/SVG/v3.c create mode 100644 applications/generators/X3D/Makefile create mode 100644 applications/generators/X3D/X3DGen.dsp create mode 100644 applications/generators/X3D/X3DGen.dsw create mode 100644 applications/generators/X3D/main.c create mode 100644 applications/generators/X3D/skip.txt create mode 100644 applications/generators/X3D/templates_X3D.txt create mode 100644 applications/m3u82mpd/m3u82mpd.vcproj create mode 100644 applications/m3u82mpd/main.c create mode 100644 applications/mp42avi/Makefile create mode 100644 applications/mp42avi/main.c create mode 100644 applications/mp42ts/Makefile create mode 100644 applications/mp42ts/main.c create mode 100644 applications/mp42ts/mp42ts.h create mode 100644 applications/mp4box/Makefile create mode 100644 applications/mp4box/filedump.c create mode 100644 applications/mp4box/fileimport.c create mode 100644 applications/mp4box/live.c create mode 100644 applications/mp4box/main.c create mode 100644 applications/mp4box/wrapper.c create mode 100644 applications/mp4client/Makefile create mode 100644 applications/mp4client/carbon_events.c create mode 100644 applications/mp4client/extract.c create mode 100644 applications/mp4client/main.c create mode 100644 applications/mp4client/mp4client.rc create mode 100644 applications/mp4client/resource.h create mode 100644 applications/testapps/bmp4demux/Makefile create mode 100644 applications/testapps/bmp4demux/bmp4demux.sln create mode 100644 applications/testapps/bmp4demux/bmp4demux.vcxproj create mode 100644 applications/testapps/bmp4demux/bmp4demux.vcxproj.filters create mode 100644 applications/testapps/bmp4demux/build.sh create mode 100644 applications/testapps/bmp4demux/main.c create mode 100644 applications/testapps/broadcaster/Makefile create mode 100644 applications/testapps/broadcaster/RTP_serv_generator.c create mode 100644 applications/testapps/broadcaster/RTP_serv_generator.h create mode 100644 applications/testapps/broadcaster/RTP_serv_packetizer.c create mode 100644 applications/testapps/broadcaster/RTP_serv_packetizer.h create mode 100644 applications/testapps/broadcaster/RTP_serv_sender.c create mode 100644 applications/testapps/broadcaster/RTP_serv_sender.h create mode 100644 applications/testapps/broadcaster/broadcaster.c create mode 100644 applications/testapps/broadcaster/broadcaster.dsp create mode 100644 applications/testapps/broadcaster/broadcaster.h create mode 100644 applications/testapps/broadcaster/broadcaster_config.cfg create mode 100644 applications/testapps/broadcaster/debug.c create mode 100644 applications/testapps/broadcaster/debug.h create mode 100644 applications/testapps/broadcaster/france.mp4 create mode 100644 applications/testapps/broadcaster/meteo_local.xmt create mode 100644 applications/testapps/broadcaster/sdp_generator.c create mode 100644 applications/testapps/broadcaster/sdp_generator.h create mode 100644 applications/testapps/dmbrs/dmbrs.dsp create mode 100644 applications/testapps/dmbrs/main.c create mode 100644 applications/testapps/fmp4demux/Makefile create mode 100755 applications/testapps/fmp4demux/build.sh create mode 100644 applications/testapps/fmp4demux/fmp4demux.sln create mode 100644 applications/testapps/fmp4demux/fmp4demux.vcxproj create mode 100644 applications/testapps/fmp4demux/fmp4demux.vcxproj.filters create mode 100644 applications/testapps/fmp4demux/main.c create mode 100644 applications/testapps/hevcbench/defbench.h create mode 100644 applications/testapps/hevcbench/hevcbench.vcxproj create mode 100644 applications/testapps/hevcbench/main.c create mode 100644 applications/testapps/largefile/largefile.dsp create mode 100644 applications/testapps/largefile/largefile.dsw create mode 100644 applications/testapps/largefile/main.c create mode 100644 applications/testapps/loadcompare/LoadCompare.dsp create mode 100644 applications/testapps/loadcompare/Makefile create mode 100644 applications/testapps/loadcompare/loadcompare.c create mode 100644 applications/testapps/mp42ts/mp42ts.vcproj create mode 100644 applications/testapps/mpedemux/Makefile create mode 100644 applications/testapps/mpedemux/main.c create mode 100644 applications/testapps/mpedemux/mpedemux.dsp create mode 100644 applications/testapps/mpeg2ts/main.c create mode 100644 applications/testapps/mpeg2ts/mpeg2ts.dsp create mode 100644 applications/testapps/segmp4demux/Makefile create mode 100644 applications/testapps/segmp4demux/build.sh create mode 100644 applications/testapps/segmp4demux/main.c create mode 100644 applications/testapps/segmp4demux/segmp4demux.sln create mode 100644 applications/testapps/segmp4demux/segmp4demux.vcxproj create mode 100644 applications/testapps/segmp4demux/segmp4demux.vcxproj.filters create mode 100644 applications/testapps/svg2bifs/main.c create mode 100644 applications/testapps/svg2bifs/svg2bifs.dsp create mode 100644 applications/ts2hds/Makefile create mode 100644 applications/ts2hds/f4m.c create mode 100644 applications/ts2hds/f4v.c create mode 100644 applications/ts2hds/main.c create mode 100644 applications/ts2hds/ts2hds.h create mode 100644 applications/udptsseg/Makefile create mode 100644 applications/udptsseg/main.c create mode 100644 applications/udptsseg/udptsseg.dsp create mode 100644 applications/udptsseg/udptsseg.vcproj create mode 100644 bin/smartphone 2003 (armv4)/release/install/archive.bat create mode 100644 bin/smartphone 2003 (armv4)/release/install/build_installer.bat create mode 100644 bin/smartphone 2003 (armv4)/release/install/gpac.inf create mode 100644 bin/smartphone 2003 (armv4)/release/install/readme.txt create mode 100755 configure create mode 100644 doc/CODING_STYLE create mode 100644 doc/GPAC UPnP.doc create mode 100644 doc/INSTALL.gcc create mode 100644 doc/INSTALL.gpe create mode 100644 doc/INSTALL.symbian create mode 100644 doc/INSTALL.w32 create mode 100644 doc/INSTALL.wCE create mode 100644 doc/ISO 639-2 codes.txt create mode 100644 doc/SceneGenerators create mode 100644 doc/configuration.html create mode 100644 doc/doxyfile create mode 100644 doc/doxyfile-full create mode 100644 doc/gpac.mp4 create mode 100644 doc/ipmpx_syntax.bt create mode 100644 doc/man/gpac.1 create mode 100644 doc/man/mp42avi.1 create mode 100644 doc/man/mp4box.1 create mode 100644 doc/man/mp4client.1 create mode 100644 doc/osmo4.ico create mode 100644 generate_installer.bat create mode 100644 gpac.spec create mode 100644 gui/extensions/H2B2VS/H2B2VS.png create mode 100644 gui/extensions/H2B2VS/h2b2vs.js create mode 100644 gui/extensions/H2B2VS/init.js create mode 100644 gui/extensions/H2B2VS/logo_hd.png create mode 100644 gui/extensions/H2B2VS/logo_uhd.png create mode 100644 gui/extensions/player/applications-multimedia.svg create mode 100644 gui/extensions/player/fileopen.js create mode 100644 gui/extensions/player/init.js create mode 100644 gui/extensions/player/player.js create mode 100644 gui/extensions/player/playlist.js create mode 100644 gui/extensions/player/stats.js create mode 100644 gui/extensions/widget_manager/applications-system.svg create mode 100644 gui/extensions/widget_manager/init.js create mode 100644 gui/gui.bt create mode 100644 gui/gui.js create mode 100644 gui/gui_old.bt create mode 100644 gui/gui_old.js create mode 100644 gui/gwlib.js create mode 100644 gui/icons/add.svg create mode 100644 gui/icons/app.svg create mode 100644 gui/icons/audio.svg create mode 100644 gui/icons/audio_full.svg create mode 100644 gui/icons/audio_mute.svg create mode 100644 gui/icons/check.svg create mode 100644 gui/icons/close.svg create mode 100644 gui/icons/cross.svg create mode 100644 gui/icons/down.svg create mode 100644 gui/icons/expand.svg create mode 100644 gui/icons/file.svg create mode 100644 gui/icons/film.svg create mode 100644 gui/icons/folder.svg create mode 100644 gui/icons/harddrive.svg create mode 100644 gui/icons/heart.svg create mode 100644 gui/icons/home.svg create mode 100644 gui/icons/image.svg create mode 100644 gui/icons/info.svg create mode 100644 gui/icons/laptop.svg create mode 100644 gui/icons/left.svg create mode 100644 gui/icons/list.svg create mode 100644 gui/icons/live.svg create mode 100644 gui/icons/media_next.svg create mode 100644 gui/icons/media_prev.svg create mode 100644 gui/icons/monitor.svg create mode 100644 gui/icons/more.svg create mode 100644 gui/icons/musical.svg create mode 100644 gui/icons/navigation.svg create mode 100644 gui/icons/network.svg create mode 100644 gui/icons/next.svg create mode 100644 gui/icons/osmo.svg create mode 100644 gui/icons/overflowing.svg create mode 100644 gui/icons/pause.svg create mode 100644 gui/icons/pl_next.svg create mode 100644 gui/icons/pl_prev.svg create mode 100644 gui/icons/play.svg create mode 100644 gui/icons/play_loop.svg create mode 100644 gui/icons/play_shuffle.svg create mode 100644 gui/icons/play_single.svg create mode 100644 gui/icons/power.svg create mode 100644 gui/icons/previous.svg create mode 100644 gui/icons/remove.svg create mode 100644 gui/icons/resize.svg create mode 100644 gui/icons/rewind.svg create mode 100644 gui/icons/right.svg create mode 100644 gui/icons/seek_forward.svg create mode 100644 gui/icons/shrink.svg create mode 100644 gui/icons/sort.svg create mode 100644 gui/icons/speed.svg create mode 100644 gui/icons/star.svg create mode 100644 gui/icons/stop.svg create mode 100644 gui/icons/stop2.svg create mode 100644 gui/icons/trash.svg create mode 100644 gui/icons/tray.svg create mode 100644 gui/icons/tv.svg create mode 100644 gui/icons/up.svg create mode 100644 gui/icons/world.svg create mode 100644 gui/iphone_wm_gui.js create mode 100644 gui/iphone_wm_gui.svg create mode 100644 gui/mpegu-wm.bt create mode 100644 gui/mpegu-wm.xmt create mode 100644 gui/tv_wm_gui.js create mode 100644 gui/tv_wm_gui.svg create mode 100644 gui/webvtt-renderer.js create mode 100644 include/gpac/ait.h create mode 100644 include/gpac/avparse.h create mode 100644 include/gpac/base_coding.h create mode 100644 include/gpac/bifs.h create mode 100644 include/gpac/bitstream.h create mode 100644 include/gpac/cache.h create mode 100644 include/gpac/color.h create mode 100644 include/gpac/compositor.h create mode 100644 include/gpac/config_file.h create mode 100644 include/gpac/configuration.h create mode 100644 include/gpac/constants.h create mode 100644 include/gpac/crypt.h create mode 100644 include/gpac/dash.h create mode 100644 include/gpac/download.h create mode 100644 include/gpac/dsmcc.h create mode 100644 include/gpac/dvb_mpe.h create mode 100644 include/gpac/esi.h create mode 100644 include/gpac/events.h create mode 100644 include/gpac/events_constants.h create mode 100644 include/gpac/filestreamer.h create mode 100644 include/gpac/html5_media.h create mode 100644 include/gpac/html5_mse.h create mode 100644 include/gpac/ietf.h create mode 100644 include/gpac/internal/avilib.h create mode 100644 include/gpac/internal/bifs_dev.h create mode 100644 include/gpac/internal/bifs_tables.h create mode 100644 include/gpac/internal/camera.h create mode 100644 include/gpac/internal/compositor_dev.h create mode 100644 include/gpac/internal/crypt_dev.h create mode 100644 include/gpac/internal/dvb_mpe_dev.h create mode 100644 include/gpac/internal/ietf_dev.h create mode 100644 include/gpac/internal/isomedia_dev.h create mode 100644 include/gpac/internal/laser_dev.h create mode 100644 include/gpac/internal/m3u8.h create mode 100644 include/gpac/internal/media_dev.h create mode 100644 include/gpac/internal/mesh.h create mode 100644 include/gpac/internal/mpd.h create mode 100644 include/gpac/internal/odf_dev.h create mode 100644 include/gpac/internal/odf_parse_common.h create mode 100644 include/gpac/internal/ogg.h create mode 100644 include/gpac/internal/reedsolomon.h create mode 100644 include/gpac/internal/scenegraph_dev.h create mode 100644 include/gpac/internal/smjs_api.h create mode 100644 include/gpac/internal/swf_dev.h create mode 100644 include/gpac/internal/terminal_dev.h create mode 100644 include/gpac/internal/vobsub.h create mode 100644 include/gpac/ismacryp.h create mode 100644 include/gpac/iso639.h create mode 100644 include/gpac/isomedia.h create mode 100644 include/gpac/laser.h create mode 100644 include/gpac/list.h create mode 100644 include/gpac/map.h create mode 100644 include/gpac/maths.h create mode 100644 include/gpac/media_tools.h create mode 100644 include/gpac/mediaobject.h create mode 100644 include/gpac/module.h create mode 100644 include/gpac/modules/audio_out.h create mode 100644 include/gpac/modules/codec.h create mode 100644 include/gpac/modules/font.h create mode 100644 include/gpac/modules/hardcoded_proto.h create mode 100644 include/gpac/modules/ipmp.h create mode 100644 include/gpac/modules/js_usr.h create mode 100644 include/gpac/modules/raster2d.h create mode 100644 include/gpac/modules/service.h create mode 100644 include/gpac/modules/term_ext.h create mode 100644 include/gpac/modules/video_out.h create mode 100644 include/gpac/mpeg4_odf.h create mode 100644 include/gpac/mpegts.h create mode 100644 include/gpac/network.h create mode 100644 include/gpac/nodes_mpeg4.h create mode 100644 include/gpac/nodes_svg.h create mode 100644 include/gpac/nodes_x3d.h create mode 100644 include/gpac/nodes_xbl.h create mode 100644 include/gpac/options.h create mode 100644 include/gpac/path2d.h create mode 100644 include/gpac/ringbuffer.h create mode 100644 include/gpac/rtp_streamer.h create mode 100644 include/gpac/scene_engine.h create mode 100644 include/gpac/scene_manager.h create mode 100644 include/gpac/scenegraph.h create mode 100644 include/gpac/scenegraph_svg.h create mode 100644 include/gpac/scenegraph_vrml.h create mode 100644 include/gpac/setup.h create mode 100644 include/gpac/svg_types.h create mode 100644 include/gpac/sync_layer.h create mode 100644 include/gpac/term_info.h create mode 100644 include/gpac/terminal.h create mode 100644 include/gpac/thread.h create mode 100644 include/gpac/token.h create mode 100644 include/gpac/tools.h create mode 100644 include/gpac/unicode.h create mode 100644 include/gpac/user.h create mode 100644 include/gpac/utf.h create mode 100644 include/gpac/version.h create mode 100644 include/gpac/webvtt.h create mode 100644 include/gpac/xml.h create mode 100644 include/win32/inttypes.h create mode 100644 include/win32/stdint.h create mode 100644 include/wince/errno.h create mode 100755 mkdmg.sh create mode 100644 modules/Makefile create mode 100644 modules/aac_in/Makefile create mode 100644 modules/aac_in/aac_in.c create mode 100644 modules/aac_in/faad_dec.c create mode 100644 modules/ac3_in/Makefile create mode 100644 modules/ac3_in/ac3_in.c create mode 100644 modules/ac3_in/liba52_dec.c create mode 100644 modules/alsa/Makefile create mode 100644 modules/alsa/alsa.c create mode 100644 modules/amr_dec/Makefile create mode 100644 modules/amr_dec/amr_dec.c create mode 100644 modules/amr_dec/amr_in.c create mode 100644 modules/amr_dec/amr_nb/typedefs.h create mode 100644 modules/amr_dec/amr_nb_api.h create mode 100644 modules/amr_float_dec/Makefile create mode 100644 modules/amr_float_dec/amr_api.h create mode 100644 modules/amr_float_dec/amr_float_dec.c create mode 100644 modules/audio_filter/Makefile create mode 100644 modules/audio_filter/audio_filter.c create mode 100644 modules/avcap/Makefile create mode 100644 modules/avcap/avcap.cpp create mode 100644 modules/bifs_dec/Makefile create mode 100644 modules/bifs_dec/bifs_dec.c create mode 100644 modules/ctx_load/Makefile create mode 100644 modules/ctx_load/ctx_load.c create mode 100644 modules/dektec_out/Makefile create mode 100644 modules/dektec_out/dektec_video.cpp create mode 100644 modules/demo_is/Makefile create mode 100644 modules/demo_is/demo-sensor.bt create mode 100644 modules/demo_is/demo_is.c create mode 100644 modules/directfb_out/Makefile create mode 100755 modules/directfb_out/directfb_out.c create mode 100755 modules/directfb_out/directfb_out.h create mode 100644 modules/directfb_out/directfb_wrapper.c create mode 100644 modules/droid_audio/droidaudio.c create mode 100644 modules/droid_audio/javaenv.c create mode 100644 modules/droid_audio/javaenv.h create mode 100644 modules/droid_cam/droid_cam.c create mode 100644 modules/droid_mpegv/droid_mpegv.c create mode 100644 modules/droid_out/droid_vout-bitmap.c create mode 100644 modules/droid_out/droid_vout.c create mode 100644 modules/dummy_in/Makefile create mode 100644 modules/dummy_in/dummy_in.c create mode 100644 modules/dx_hw/Makefile create mode 100644 modules/dx_hw/collide.cur create mode 100644 modules/dx_hw/copy_pixels.c create mode 100644 modules/dx_hw/dx_2d.c create mode 100644 modules/dx_hw/dx_audio.c create mode 100644 modules/dx_hw/dx_hw.h create mode 100644 modules/dx_hw/dx_hw.rc create mode 100644 modules/dx_hw/dx_video.c create mode 100644 modules/dx_hw/dx_window.c create mode 100644 modules/dx_hw/hand.cur create mode 100644 modules/dx_hw/resource.h create mode 100644 modules/epoc_hw/epoc_aout.cpp create mode 100644 modules/epoc_hw/epoc_codec.cpp create mode 100644 modules/epoc_hw/epoc_vout.cpp create mode 100644 modules/ffmpeg_in/Makefile create mode 100644 modules/ffmpeg_in/ffmpeg_decode.c create mode 100644 modules/ffmpeg_in/ffmpeg_demux.c create mode 100644 modules/ffmpeg_in/ffmpeg_in.h create mode 100644 modules/ffmpeg_in/ffmpeg_load.c create mode 100644 modules/freenect/Makefile create mode 100644 modules/freenect/freenect.c create mode 100644 modules/ft_font/Makefile create mode 100644 modules/ft_font/ft_font.c create mode 100644 modules/ft_font/ft_font.h create mode 100644 modules/gapi/gapi.cpp create mode 100644 modules/gapi/gapi.h create mode 100644 modules/gdip_raster/gdip_font.cpp create mode 100644 modules/gdip_raster/gdip_grad.cpp create mode 100644 modules/gdip_raster/gdip_priv.h create mode 100644 modules/gdip_raster/gdip_rend.cpp create mode 100644 modules/gdip_raster/gdip_texture.cpp create mode 100644 modules/gpac_js/Makefile create mode 100644 modules/gpac_js/gpac_js.c create mode 100644 modules/hyb_in/Makefile create mode 100644 modules/hyb_in/fm_fake_pull.c create mode 100644 modules/hyb_in/fm_fake_push.c create mode 100644 modules/hyb_in/fm_mmbtools.c create mode 100644 modules/hyb_in/hyb_in.c create mode 100644 modules/hyb_in/hyb_in.h create mode 100644 modules/img_in/Makefile create mode 100644 modules/img_in/bmp_dec.c create mode 100644 modules/img_in/img_dec.c create mode 100644 modules/img_in/img_in.c create mode 100644 modules/img_in/img_in.h create mode 100644 modules/img_in/jp2_dec.c create mode 100644 modules/img_in/jpeg_dec.c create mode 100644 modules/img_in/png_dec.c create mode 100644 modules/ios_cam/CameraObject.h create mode 100644 modules/ios_cam/CameraObject.m create mode 100644 modules/ios_cam/cam_wrap.h create mode 100644 modules/ios_cam/cam_wrap.m create mode 100644 modules/ios_cam/ios_cam.c create mode 100644 modules/ios_mpegv/SensorAcces.m create mode 100644 modules/ios_mpegv/SensorAccess.h create mode 100644 modules/ios_mpegv/ios_mpegv-Prefix.pch create mode 100644 modules/ios_mpegv/ios_mpegv.c create mode 100644 modules/ios_mpegv/sensor_wrap.h create mode 100644 modules/ismacryp/Makefile create mode 100644 modules/ismacryp/isma_ea.c create mode 100644 modules/isom_in/Makefile create mode 100644 modules/isom_in/isom_cache.c create mode 100644 modules/isom_in/isom_in.h create mode 100644 modules/isom_in/load.c create mode 100644 modules/isom_in/read.c create mode 100644 modules/isom_in/read_ch.c create mode 100644 modules/jack/Makefile create mode 100644 modules/jack/jack.c create mode 100644 modules/laser_dec/Makefile create mode 100644 modules/laser_dec/laser_dec.c create mode 100644 modules/libplayer/Makefile create mode 100644 modules/libplayer/libplayer.c create mode 100644 modules/modules_export.cpp create mode 100644 modules/mp3_in/Makefile create mode 100644 modules/mp3_in/mad_dec.c create mode 100644 modules/mp3_in/mp3_in.c create mode 100644 modules/mpd_in/Makefile create mode 100644 modules/mpd_in/mpd_in.c create mode 100644 modules/mpegts_in/Makefile create mode 100644 modules/mpegts_in/mpegts_in.c create mode 100644 modules/mse_in/Makefile create mode 100644 modules/mse_in/mse_in.c create mode 100644 modules/odf_dec/Makefile create mode 100644 modules/odf_dec/odf_dec.c create mode 100644 modules/ogg/Makefile create mode 100644 modules/ogg/ogg_in.c create mode 100644 modules/ogg/ogg_in.h create mode 100644 modules/ogg/ogg_load.c create mode 100644 modules/ogg/theora_dec.c create mode 100644 modules/ogg/vorbis_dec.c create mode 100644 modules/opencv_is/Makefile create mode 100644 modules/opencv_is/demo-sensor.bt create mode 100644 modules/opencv_is/haarcascade_frontalface_default.xml create mode 100644 modules/opencv_is/opencv_is.c create mode 100644 modules/openhevc_dec/Makefile create mode 100644 modules/openhevc_dec/openhevc_dec.c create mode 100644 modules/opensvc_dec/Makefile create mode 100644 modules/opensvc_dec/opensvc_dec.c create mode 100644 modules/osd/Makefile create mode 100644 modules/osd/osd.c create mode 100644 modules/oss_audio/Makefile create mode 100644 modules/oss_audio/oss.c create mode 100644 modules/platinum/GPACFileMediaServer.cpp create mode 100644 modules/platinum/GPACFileMediaServer.h create mode 100644 modules/platinum/GPACMediaController.cpp create mode 100644 modules/platinum/GPACMediaController.h create mode 100644 modules/platinum/GPACMediaRenderer.cpp create mode 100644 modules/platinum/GPACMediaRenderer.h create mode 100644 modules/platinum/GPACPlatinum.cpp create mode 100644 modules/platinum/GPACPlatinum.h create mode 100644 modules/platinum/GenericDevice.cpp create mode 100644 modules/platinum/GenericDevice.h create mode 100644 modules/platinum/Makefile create mode 100644 modules/pulseaudio/Makefile create mode 100644 modules/pulseaudio/pulseaudio.c create mode 100644 modules/raw_out/Makefile create mode 100644 modules/raw_out/raw_video.c create mode 100644 modules/redirect_av/Makefile create mode 100644 modules/redirect_av/ffmpeg_ts_muxer.c create mode 100644 modules/redirect_av/gpac_ts_muxer.c create mode 100644 modules/redirect_av/redirect_av.c create mode 100644 modules/redirect_av/ts_muxer.h create mode 100644 modules/rtp_in/Makefile create mode 100644 modules/rtp_in/rtp_in.c create mode 100644 modules/rtp_in/rtp_in.h create mode 100644 modules/rtp_in/rtp_session.c create mode 100644 modules/rtp_in/rtp_signaling.c create mode 100644 modules/rtp_in/rtp_stream.c create mode 100644 modules/rtp_in/sdp_fetch.c create mode 100644 modules/rtp_in/sdp_load.c create mode 100644 modules/rvc_dec/Makefile create mode 100644 modules/rvc_dec/rvc_dec.c create mode 100644 modules/saf_in/Makefile create mode 100644 modules/saf_in/saf_in.c create mode 100644 modules/sdl_out/Makefile create mode 100644 modules/sdl_out/audio.c create mode 100644 modules/sdl_out/cursors.c create mode 100644 modules/sdl_out/sdl_out.c create mode 100644 modules/sdl_out/sdl_out.h create mode 100644 modules/sdl_out/video.c create mode 100644 modules/sdl_out/video2d.c create mode 100644 modules/soft_raster/Makefile create mode 100644 modules/soft_raster/ftgrays.c create mode 100644 modules/soft_raster/rast_soft.h create mode 100644 modules/soft_raster/raster_565.c create mode 100644 modules/soft_raster/raster_argb.c create mode 100644 modules/soft_raster/raster_load.c create mode 100644 modules/soft_raster/raster_rgb.c create mode 100644 modules/soft_raster/stencil.c create mode 100644 modules/soft_raster/surface.c create mode 100644 modules/svg_in/Makefile create mode 100644 modules/svg_in/svg_in.c create mode 100644 modules/timedtext/Makefile create mode 100644 modules/timedtext/timedtext_dec.c create mode 100644 modules/timedtext/timedtext_in.c create mode 100644 modules/ui_rec/Makefile create mode 100644 modules/ui_rec/readme.txt create mode 100644 modules/ui_rec/ui_rec.c create mode 100644 modules/validator/Makefile create mode 100644 modules/validator/README.TXT create mode 100644 modules/validator/validator.c create mode 100644 modules/vtt_in/Makefile create mode 100644 modules/vtt_in/vtt_dec.c create mode 100644 modules/vtt_in/vtt_in.c create mode 100644 modules/wav_out/Makefile create mode 100644 modules/wav_out/wav_out.c create mode 100644 modules/widgetman/Makefile create mode 100644 modules/widgetman/unzip.c create mode 100644 modules/widgetman/unzip.h create mode 100644 modules/widgetman/wgt_load.c create mode 100644 modules/widgetman/wgt_load_base.js create mode 100644 modules/widgetman/widget.c create mode 100644 modules/widgetman/widgetman.c create mode 100644 modules/widgetman/widgetman.h create mode 100644 modules/wiiis/Makefile create mode 100644 modules/wiiis/test_wii.bt create mode 100644 modules/wiiis/wiiis.c create mode 100644 modules/x11_out/Makefile create mode 100644 modules/x11_out/x11_out.c create mode 100644 modules/x11_out/x11_out.h create mode 100644 modules/xvid_dec/Makefile create mode 100644 modules/xvid_dec/xvid_dec.c create mode 100644 modules/xvid_dec/xvid_dec_wce.cpp create mode 100644 packagers/win32_64/nsis/default.out create mode 100644 packagers/win32_64/nsis/gpac_installer.nsi create mode 100644 packagers/win32_64/nsis/readme.txt create mode 100644 regression_tests/_mozilla_ie_action.html create mode 100644 regression_tests/_mozilla_ie_simple.html create mode 100644 regression_tests/_ppc_action.html create mode 100644 regression_tests/_ppc_simple.html create mode 100644 regression_tests/auxiliary_files/count_arabic.mp3 create mode 100644 regression_tests/auxiliary_files/count_english.mp3 create mode 100644 regression_tests/auxiliary_files/count_french.mp3 create mode 100644 regression_tests/auxiliary_files/count_german.mp3 create mode 100644 regression_tests/auxiliary_files/count_italian.mp3 create mode 100644 regression_tests/auxiliary_files/count_spanish.mp3 create mode 100644 regression_tests/auxiliary_files/count_video.cmp create mode 100644 regression_tests/auxiliary_files/enst_audio.aac create mode 100644 regression_tests/auxiliary_files/enst_video.h264 create mode 100644 regression_tests/auxiliary_files/index2batch.xslt create mode 100644 regression_tests/auxiliary_files/index2html.xslt create mode 100644 regression_tests/auxiliary_files/index2sh.xslt create mode 100644 regression_tests/auxiliary_files/logo.bt create mode 100644 regression_tests/auxiliary_files/logo.jpg create mode 100644 regression_tests/auxiliary_files/logo.png create mode 100644 regression_tests/auxiliary_files/nefertiti.wrl create mode 100644 regression_tests/auxiliary_files/sky.jpg create mode 100644 regression_tests/auxiliary_files/subtitle.srt create mode 100644 regression_tests/auxiliary_files/subtitle_fr.srt create mode 100644 regression_tests/auxiliary_files/svg2html.xslt create mode 100644 regression_tests/auxiliary_files/x3d2html.xslt create mode 100644 regression_tests/auxiliary_files/xmt2html.xslt create mode 100644 regression_tests/bifs/bifs-2D-background-background2D-bind.bt create mode 100644 regression_tests/bifs/bifs-2D-background-background2D-image.bt create mode 100644 regression_tests/bifs/bifs-2D-background-background2D-layer2D.bt create mode 100644 regression_tests/bifs/bifs-2D-background-background2D-movie.bt create mode 100644 regression_tests/bifs/bifs-2D-background-background2D-url-change.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-discsensor.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-htk-sensor.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-keysensor.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-mousesensor.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-nested-sensors.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-planesensor2D.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-proximitysensor2D.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-stringsensor.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-touchsensor-4states.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-touchsensor-hitpoint.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-touchsensor-isactive-exposedfield.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-touchsensor-isactive.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-touchsensor-isover.bt create mode 100644 regression_tests/bifs/bifs-2D-interactivity-touchsensor-move_over.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-colortransform-alpha.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-colortransform-bitmap.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-colortransform-color.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-lineproperties.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-material2D.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-cap.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-compositetexture2D.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-dash.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-imagetexture.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-join.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-lineargradient.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-radialgradient.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-scalable.bt create mode 100644 regression_tests/bifs/bifs-2D-painting-xlineproperties-transparent.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-clipper2D.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-form-align-center.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-form-align-horiz.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-form-align-vert.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-form-spread-horiz.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-form-spread-vert.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layer2D.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layer2d-in-layer2d.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-horiz-ltr-nowrap.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-horiz-ltr-wrap-btt.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-horiz-ltr-wrap-ttb.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-horiz-rtl-nowrap.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-horiz-rtl-wrap-btt.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-horiz-rtl-wrap-ttb.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-horiz-text.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-scroll-child.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-scroll-full.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-scroll-modes-horiz.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-scroll-modes-vert.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-scroll-on-off.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-vert-btt-nowrap.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-vert-btt-wrap-ltr.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-vert-btt-wrap-rtl.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-vert-ttb-nowrap.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-vert-ttb-wrap-ltr.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-layout-vert-ttb-wrap-rtl.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-orderedgroup.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-pathlayout-graphics.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-pathlayout.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-transform2D.bt create mode 100644 regression_tests/bifs/bifs-2D-positioning-transformmatrix2D.bt create mode 100644 regression_tests/bifs/bifs-2D-shapes-all.bt create mode 100644 regression_tests/bifs/bifs-2D-shapes-indexfaceset2D.bt create mode 100644 regression_tests/bifs/bifs-2D-shapes-indexlineset2D.bt create mode 100644 regression_tests/bifs/bifs-2D-shapes-pointset2D.bt create mode 100644 regression_tests/bifs/bifs-2D-shapes-xcurve2D.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-compositetexture2D-background.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-compositetexture2D-bitmap.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-compositetexture2D-transparent.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-gradients-text.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-gradients-transparent.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-imagetexture-shapes.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-lineargradient-simple.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-lineargradient-spread.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-movietexture-shapes.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-pixeltexture.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-radialgradient-simple.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-radialgradient-spread.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-texturetransform-base.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-texturetransform-interact.bt create mode 100644 regression_tests/bifs/bifs-2D-texturing-texturetransform-transformmatrix2D.bt create mode 100644 regression_tests/bifs/bifs-2D-viewport-complete.bt create mode 100644 regression_tests/bifs/bifs-2D-viewport-simple.bt create mode 100644 regression_tests/bifs/bifs-3D-background-images.bt create mode 100644 regression_tests/bifs/bifs-3D-background.bt create mode 100644 regression_tests/bifs/bifs-3D-interactivity-collision-proxy.bt create mode 100644 regression_tests/bifs/bifs-3D-interactivity-collision.bt create mode 100644 regression_tests/bifs/bifs-3D-interactivity-cylindersensor.bt create mode 100644 regression_tests/bifs/bifs-3D-interactivity-planesensor.bt create mode 100644 regression_tests/bifs/bifs-3D-interactivity-proximitysensor.bt create mode 100644 regression_tests/bifs/bifs-3D-interactivity-spheresensor.bt create mode 100644 regression_tests/bifs/bifs-3D-interactivity-visibilitysensor.bt create mode 100644 regression_tests/bifs/bifs-3D-lighting-directionalLight.bt create mode 100644 regression_tests/bifs/bifs-3D-lighting-fog.bt create mode 100644 regression_tests/bifs/bifs-3D-lighting-pointlight.bt create mode 100644 regression_tests/bifs/bifs-3D-lighting-spotlight.bt create mode 100644 regression_tests/bifs/bifs-3D-positioning-billboard-viewer-alignment.bt create mode 100644 regression_tests/bifs/bifs-3D-positioning-billboard.bt create mode 100644 regression_tests/bifs/bifs-3D-positioning-gravity.bt create mode 100644 regression_tests/bifs/bifs-3D-positioning-layer3D-views.bt create mode 100644 regression_tests/bifs/bifs-3D-positioning-layer3D.bt create mode 100644 regression_tests/bifs/bifs-3D-positioning-lod.bt create mode 100644 regression_tests/bifs/bifs-3D-positioning-transform.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-box-transparent.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-box.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-cone.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-cylinder.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-elevationgrid.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-extrusion.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-indexedfaceset.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-indexedlineset.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-nonlineardeformer.bt create mode 100644 regression_tests/bifs/bifs-3D-shapes-pointset.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-box-transparent.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-box-video.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-box.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-compositetexture3D-bitmap.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-compositetexture3D-box.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-cone-transparent.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-cone.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-cylinder-transparent.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-cylinder.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-transform-box.bt create mode 100644 regression_tests/bifs/bifs-3D-texturing-transform-matrix-box.bt create mode 100644 regression_tests/bifs/bifs-3D-viewpoint-anim.bt create mode 100644 regression_tests/bifs/bifs-3D-viewpoint-bind-jump.bt create mode 100644 regression_tests/bifs/bifs-3D-viewpoint-bind.bt create mode 100644 regression_tests/bifs/bifs-3D-viewpoint-ortho-bind.bt create mode 100644 regression_tests/bifs/bifs-bitmap-image-meter-metrics.bt create mode 100644 regression_tests/bifs/bifs-bitmap-image-pixel-metrics.bt create mode 100644 regression_tests/bifs/bifs-bitmap-image-resizing.bt create mode 100644 regression_tests/bifs/bifs-bitmap-movie-materialkey.bt create mode 100644 regression_tests/bifs/bifs-bitmap-movie.bt create mode 100644 regression_tests/bifs/bifs-bitmap-video-resizing.bt create mode 100644 regression_tests/bifs/bifs-cachetexture_cache.bt create mode 100644 regression_tests/bifs/bifs-cachetexture_nocache.bt create mode 100644 regression_tests/bifs/bifs-command-animated-osmo4logo.bt create mode 100644 regression_tests/bifs/bifs-command-delete-index.bt create mode 100644 regression_tests/bifs/bifs-command-delete-node.bt create mode 100644 regression_tests/bifs/bifs-command-delete-route.bt create mode 100644 regression_tests/bifs/bifs-command-global-qp.bt create mode 100644 regression_tests/bifs/bifs-command-insert-index.bt create mode 100644 regression_tests/bifs/bifs-command-insert-node.bt create mode 100644 regression_tests/bifs/bifs-command-insert-nodedef.bt create mode 100644 regression_tests/bifs/bifs-command-insert-route.bt create mode 100644 regression_tests/bifs/bifs-command-multiple-replace-field.bt create mode 100644 regression_tests/bifs/bifs-command-multiple-replace-index.bt create mode 100644 regression_tests/bifs/bifs-command-node-delete-ex.bt create mode 100644 regression_tests/bifs/bifs-command-proto-delete.bt create mode 100644 regression_tests/bifs/bifs-command-proto-insert.bt create mode 100644 regression_tests/bifs/bifs-command-protolist-delete.bt create mode 100644 regression_tests/bifs/bifs-command-quantification.bt create mode 100644 regression_tests/bifs/bifs-command-replace-field.bt create mode 100644 regression_tests/bifs/bifs-command-replace-index.bt create mode 100644 regression_tests/bifs/bifs-command-replace-node-null.bt create mode 100644 regression_tests/bifs/bifs-command-replace-node.bt create mode 100644 regression_tests/bifs/bifs-command-replace-route.bt create mode 100644 regression_tests/bifs/bifs-command-replace-scene-null.bt create mode 100644 regression_tests/bifs/bifs-command-replace-scene.bt create mode 100644 regression_tests/bifs/bifs-command-route-add-children.bt create mode 100644 regression_tests/bifs/bifs-command-route-children.bt create mode 100644 regression_tests/bifs/bifs-command-route-node-exposedfield.bt create mode 100644 regression_tests/bifs/bifs-command-route-node.bt create mode 100644 regression_tests/bifs/bifs-command-route-remove-children.bt create mode 100644 regression_tests/bifs/bifs-environmenttest.bt create mode 100644 regression_tests/bifs/bifs-externproto-forestgump-lib.bt create mode 100644 regression_tests/bifs/bifs-externproto-forestgump.bt create mode 100644 regression_tests/bifs/bifs-externproto-mfurl-lib.bt create mode 100644 regression_tests/bifs/bifs-externproto-mfurl.bt create mode 100644 regression_tests/bifs/bifs-externproto-nood-lib.bt create mode 100644 regression_tests/bifs/bifs-externproto-nood.bt create mode 100644 regression_tests/bifs/bifs-externproto-simple-lib.bt create mode 100644 regression_tests/bifs/bifs-externproto-simple.bt create mode 100644 regression_tests/bifs/bifs-game-arrange.bt create mode 100644 regression_tests/bifs/bifs-game-breakout.bt create mode 100644 regression_tests/bifs/bifs-game-bubble.bt create mode 100644 regression_tests/bifs/bifs-game-minesweeper.bt create mode 100644 regression_tests/bifs/bifs-game-othello.bt create mode 100644 regression_tests/bifs/bifs-interpolation-colorinterpolator.bt create mode 100644 regression_tests/bifs/bifs-interpolation-coordinateinterpolator2D.bt create mode 100644 regression_tests/bifs/bifs-interpolation-positionanimator.bt create mode 100644 regression_tests/bifs/bifs-interpolation-positionanimator2D.bt create mode 100644 regression_tests/bifs/bifs-interpolation-positioninterpolator-position.bt create mode 100644 regression_tests/bifs/bifs-interpolation-positioninterpolator-size.bt create mode 100644 regression_tests/bifs/bifs-interpolation-positioninterpolator2D-position.bt create mode 100644 regression_tests/bifs/bifs-interpolation-positioninterpolator2D-size.bt create mode 100644 regression_tests/bifs/bifs-interpolation-scalaranimator.bt create mode 100644 regression_tests/bifs/bifs-interpolation-scalarinterpolator.bt create mode 100644 regression_tests/bifs/bifs-interpolation-timesensor-enabled.bt create mode 100644 regression_tests/bifs/bifs-interpolation-timesensor-starttime_norestart.bt create mode 100644 regression_tests/bifs/bifs-interpolation-timesensor-starttime_restart.bt create mode 100644 regression_tests/bifs/bifs-interpolation-valuator-sftime.bt create mode 100644 regression_tests/bifs/bifs-keynavigator.bt create mode 100644 regression_tests/bifs/bifs-linking-anchor-mp4-next.bt create mode 100644 regression_tests/bifs/bifs-linking-anchor-mp4-prev.bt create mode 100644 regression_tests/bifs/bifs-linking-anchor-viewpoint.bt create mode 100644 regression_tests/bifs/bifs-linking-anchor-www.bt create mode 100644 regression_tests/bifs/bifs-linking-animationstream.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-direct-inline.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-direct.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-od-inline.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-od.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-rtsp-no-od.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-rtsp.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-segment-inline.bt create mode 100644 regression_tests/bifs/bifs-linking-inline-segment.bt create mode 100644 regression_tests/bifs/bifs-media-audiobuffer.bt create mode 100644 regression_tests/bifs/bifs-media-audioclip-urlchanged.bt create mode 100644 regression_tests/bifs/bifs-media-audioclip.bt create mode 100644 regression_tests/bifs/bifs-media-audiosource-mixing.bt create mode 100644 regression_tests/bifs/bifs-media-audiosource-urlchanged.bt create mode 100644 regression_tests/bifs/bifs-media-audiosource.bt create mode 100644 regression_tests/bifs/bifs-media-imagetexture-OD-reuse.bt create mode 100644 regression_tests/bifs/bifs-media-imagetexture-no-od.bt create mode 100644 regression_tests/bifs/bifs-media-imagetexture-object-scale.bt create mode 100644 regression_tests/bifs/bifs-media-imagetexture-transparent.bt create mode 100644 regression_tests/bifs/bifs-media-imagetexture-url-change.bt create mode 100644 regression_tests/bifs/bifs-media-movietexture-control.bt create mode 100644 regression_tests/bifs/bifs-media-movietexture-no-od.bt create mode 100644 regression_tests/bifs/bifs-media-movietexture-od-joinsession.bt create mode 100644 regression_tests/bifs/bifs-media-movietexture-od-leave-session.bt create mode 100644 regression_tests/bifs/bifs-media-movietexture-owns-OCR.bt create mode 100644 regression_tests/bifs/bifs-media-movietexture-shares-OCR.bt create mode 100644 regression_tests/bifs/bifs-media-movietexture-url-change.bt create mode 100644 regression_tests/bifs/bifs-media-sound-spatialize.bt create mode 100644 regression_tests/bifs/bifs-media-sound.bt create mode 100644 regression_tests/bifs/bifs-misc-UTF16-input.bt create mode 100644 regression_tests/bifs/bifs-misc-cyclic-graph.bt create mode 100644 regression_tests/bifs/bifs-misc-hc-proto-events.bt create mode 100644 regression_tests/bifs/bifs-misc-hc-proto-pathextrusion.bt create mode 100644 regression_tests/bifs/bifs-misc-hc-proto-planarextrusion.bt create mode 100644 regression_tests/bifs/bifs-misc-hc-proto-planeclipper.bt create mode 100644 regression_tests/bifs/bifs-misc-non-linear-parsing-conditional.bt create mode 100644 regression_tests/bifs/bifs-misc-non-linear-parsing-use.bt create mode 100644 regression_tests/bifs/bifs-misc-srt-import-3gpp-control-share-ocr.bt create mode 100644 regression_tests/bifs/bifs-misc-srt-import-3gpp-control.bt create mode 100644 regression_tests/bifs/bifs-misc-srt-import-3gpp.bt create mode 100644 regression_tests/bifs/bifs-misc-srt-import.bt create mode 100644 regression_tests/bifs/bifs-od-remove-esd.bt create mode 100644 regression_tests/bifs/bifs-od-remove-od.bt create mode 100644 regression_tests/bifs/bifs-od-update-od.bt create mode 100644 regression_tests/bifs/bifs-proto-conditional.bt create mode 100644 regression_tests/bifs/bifs-proto-delete-def.bt create mode 100644 regression_tests/bifs/bifs-proto-delete-index.bt create mode 100644 regression_tests/bifs/bifs-proto-forestgump.bt create mode 100644 regression_tests/bifs/bifs-proto-mfurl.bt create mode 100644 regression_tests/bifs/bifs-proto-multiple.bt create mode 100644 regression_tests/bifs/bifs-proto-nested.bt create mode 100644 regression_tests/bifs/bifs-proto-route.bt create mode 100644 regression_tests/bifs/bifs-proto-sftime-protocode.bt create mode 100644 regression_tests/bifs/bifs-proto-sftime-protointerface.bt create mode 100644 regression_tests/bifs/bifs-proto-simple.bt create mode 100644 regression_tests/bifs/bifs-proto-use.bt create mode 100644 regression_tests/bifs/bifs-script-char-to-int.bt create mode 100644 regression_tests/bifs/bifs-script-child-create.bt create mode 100644 regression_tests/bifs/bifs-script-date.bt create mode 100644 regression_tests/bifs/bifs-script-event-out.bt create mode 100644 regression_tests/bifs/bifs-script-initialize.bt create mode 100644 regression_tests/bifs/bifs-script-load-url.bt create mode 100644 regression_tests/bifs/bifs-script-node-access.bt create mode 100644 regression_tests/bifs/bifs-script-node-create.bt create mode 100644 regression_tests/bifs/bifs-script-proto.bt create mode 100644 regression_tests/bifs/bifs-script-timestamp.bt create mode 100644 regression_tests/bifs/bifs-storage.bt create mode 100644 regression_tests/bifs/bifs-stream-text-switch.bt create mode 100644 regression_tests/bifs/bifs-text-align-horiz1.bt create mode 100644 regression_tests/bifs/bifs-text-align-horiz2.bt create mode 100644 regression_tests/bifs/bifs-text-align-horiz3.bt create mode 100644 regression_tests/bifs/bifs-text-align-horiz4.bt create mode 100644 regression_tests/bifs/bifs-text-align-vert1.bt create mode 100644 regression_tests/bifs/bifs-text-align-vert2.bt create mode 100644 regression_tests/bifs/bifs-text-align-vert3.bt create mode 100644 regression_tests/bifs/bifs-text-align-vert4.bt create mode 100644 regression_tests/bifs/bifs-text-glyph-advance.bt create mode 100644 regression_tests/bifs/bifs-text-length.bt create mode 100644 regression_tests/bifs/bifs-text-maxextend.bt create mode 100644 regression_tests/bifs/bifs-text-style.bt create mode 100644 regression_tests/bifs/bifs-text-unicode.bt create mode 100644 regression_tests/bifs/bifs-text-vrml-alignment.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-OCR.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-audio-speed.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-audio.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-complete.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-deactivation.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-inline-av.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-inline-segments.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-inline.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-rtsp.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-seg-inline.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-segments.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-video.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-videospeed.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediasensor-segment-switch.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediasensor-segment.bt create mode 100644 regression_tests/bifs/bifs-timeline-mediasensor.bt create mode 100755 regression_tests/build-navigator-sh create mode 100644 regression_tests/build-navigator-w32.bat create mode 100644 regression_tests/build-shell create mode 100644 regression_tests/build-w32.bat create mode 100644 regression_tests/dom/gpac-dom-portability.js create mode 100644 regression_tests/dom/gpac-html-portability.js create mode 100644 regression_tests/html5_video/basic_arraybuffer.js create mode 100644 regression_tests/html5_video/basic_audio.svg create mode 100644 regression_tests/html5_video/basic_mediasource.js create mode 100644 regression_tests/html5_video/basic_sourcebuffer.js create mode 100644 regression_tests/html5_video/basic_url.js create mode 100644 regression_tests/html5_video/basic_video.js create mode 100644 regression_tests/html5_video/basic_video.svg create mode 100644 regression_tests/html5_video/bind.js create mode 100644 regression_tests/html5_video/counter-mp4-audio-segments-http.js create mode 100644 regression_tests/html5_video/counter-mp4-av-segments-http.js create mode 100644 regression_tests/html5_video/counter-mp4-video-segments-http.js create mode 100644 regression_tests/html5_video/counter-mp4-video-segments-live-nobs-http.js create mode 100644 regression_tests/html5_video/counter-mp4-video-segments-local.js create mode 100644 regression_tests/html5_video/file.json create mode 100644 regression_tests/html5_video/file.txt create mode 100644 regression_tests/html5_video/file.xml create mode 100644 regression_tests/html5_video/gpac-mse-spatial.js create mode 100644 regression_tests/html5_video/gpac-mse.js create mode 100644 regression_tests/html5_video/implementation_notes.txt create mode 100644 regression_tests/html5_video/mediaevents.js create mode 100644 regression_tests/html5_video/mediaevents.svg create mode 100644 regression_tests/html5_video/mse-overlap.js create mode 100644 regression_tests/html5_video/mse.svg create mode 100644 regression_tests/html5_video/myanmar-tiles.js create mode 100644 regression_tests/html5_video/nodejs-byte-server.js create mode 100644 regression_tests/html5_video/redbull-mp4-audio-segments-http.js create mode 100644 regression_tests/html5_video/redbull-mp4-video-segments-http.js create mode 100644 regression_tests/html5_video/spatial-mse.svg create mode 100644 regression_tests/html5_video/two-videos.svg create mode 100644 regression_tests/html5_video/video.svg create mode 100644 regression_tests/html5_video/xhr.js create mode 100644 regression_tests/html5_video/xhr.svg create mode 100644 regression_tests/index.css create mode 100644 regression_tests/index.xml create mode 100644 regression_tests/svg/all_syntaxes_1.1F2.svg create mode 100644 regression_tests/svg/createanim-by-script.svg create mode 100644 regression_tests/svg/createimage-by-script.svg create mode 100644 regression_tests/svg/utfscript.svg create mode 100644 regression_tests/ttml/ebu-ttd_sample.ttml create mode 100644 regression_tests/ttml/ebu-ttd_sample_invalid_ns.ttml create mode 100644 regression_tests/ttml/ebu-ttd_sample_span.ttml create mode 100644 regression_tests/ttml/ebu-ttd_timing_contiguous.ttml create mode 100644 regression_tests/ttml/ebu-ttd_timing_non-contiguous.ttml create mode 100644 regression_tests/ttml/ebu-ttd_timing_overlapping_fail.ttml create mode 100644 regression_tests/utfscript.svg create mode 100644 regression_tests/webvtt/comments.vtt create mode 100644 regression_tests/webvtt/concatenation.vtt create mode 100644 regression_tests/webvtt/counter.srt create mode 100644 regression_tests/webvtt/counter.vtt create mode 100644 regression_tests/webvtt/elephants-dream-chapters-en.vtt create mode 100644 regression_tests/webvtt/elephants-dream-subtitles-de.vtt create mode 100644 regression_tests/webvtt/elephants-dream-subtitles-en.vtt create mode 100644 regression_tests/webvtt/empty.vtt create mode 100644 regression_tests/webvtt/empty2.vtt create mode 100644 regression_tests/webvtt/empty3.vtt create mode 100644 regression_tests/webvtt/empty4.vtt create mode 100644 regression_tests/webvtt/header.vtt create mode 100644 regression_tests/webvtt/invalid1.vtt create mode 100644 regression_tests/webvtt/invalid2.vtt create mode 100644 regression_tests/webvtt/invalid3.vtt create mode 100644 regression_tests/webvtt/invalid4.vtt create mode 100644 regression_tests/webvtt/invalid5.vtt create mode 100644 regression_tests/webvtt/long-duration.vtt create mode 100644 regression_tests/webvtt/multiline-header-additional.vtt create mode 100644 regression_tests/webvtt/multiline-header-id-invalid.vtt create mode 100644 regression_tests/webvtt/multiline-header-id.vtt create mode 100644 regression_tests/webvtt/multiline-header.vtt create mode 100644 regression_tests/webvtt/overlapping-end.vtt create mode 100644 regression_tests/webvtt/overlapping-middle.vtt create mode 100644 regression_tests/webvtt/overlapping-rewritten.vtt create mode 100644 regression_tests/webvtt/overlapping-start.vtt create mode 100644 regression_tests/webvtt/overlapping.vtt create mode 100644 regression_tests/webvtt/simple.vtt create mode 100644 regression_tests/webvtt/spaces.vtt create mode 100644 regression_tests/webvtt/spec-example-basic.vtt create mode 100644 regression_tests/webvtt/spec-example-comment.vtt create mode 100644 regression_tests/webvtt/spec-example-comment2.vtt create mode 100644 regression_tests/webvtt/spec-example-identifier.vtt create mode 100644 regression_tests/webvtt/spec-example-multiple-lines.vtt create mode 100644 regression_tests/webvtt/spec-example-nested.vtt create mode 100644 regression_tests/webvtt/spec-example-voice.vtt create mode 100644 regression_tests/webvtt/svg.vtt create mode 100644 regression_tests/webvtt/timestamps-invalid.vtt create mode 100644 regression_tests/webvtt/timestamps.vtt create mode 100644 regression_tests/x3d/x3d-2D-Arc2d.x3dv create mode 100644 regression_tests/x3d/x3d-2D-ArcClose2d.x3dv create mode 100644 regression_tests/x3d/x3d-2D-Disk2d.x3dv create mode 100644 regression_tests/x3d/x3d-2D-Polyline2d.x3dv create mode 100644 regression_tests/x3d/x3d-2D-Polypoint2d.x3dv create mode 100644 regression_tests/x3d/x3d-2D-TriangleSet2d.x3dv create mode 100644 regression_tests/x3d/x3d-3D-IndexedTriangleFanSet.x3dv create mode 100644 regression_tests/x3d/x3d-3D-IndexedTriangleSet.x3dv create mode 100644 regression_tests/x3d/x3d-3D-IndexedTriangleStripSet.x3dv create mode 100644 regression_tests/x3d/x3d-3D-LineSet.x3dv create mode 100644 regression_tests/x3d/x3d-3D-TriangleFanSet.x3dv create mode 100644 regression_tests/x3d/x3d-3D-TriangleSet.x3dv create mode 100644 regression_tests/x3d/x3d-3D-TriangleStripSet.x3dv create mode 100644 regression_tests/x3d/x3d-misc-ColorRGBA.x3dv create mode 100644 regression_tests/x3d/x3d-misc-HatchStyle.x3dv create mode 100644 regression_tests/x3d/x3d-misc-KeySensor.x3dv create mode 100644 regression_tests/x3d/x3d-misc-StringSensor.x3dv create mode 100644 regression_tests/xmlin4/ebu-ttd_sample.ttml create mode 100644 regression_tests/xmlin4/first.xml create mode 100644 regression_tests/xmlin4/input.txt create mode 100644 regression_tests/xmlin4/input.xml create mode 100644 regression_tests/xmlin4/last.xml create mode 100644 regression_tests/xmlin4/meta-mett-no-mime.nhml create mode 100644 regression_tests/xmlin4/meta-mett-xml-header.nhml create mode 100644 regression_tests/xmlin4/meta-mett-xml.nhml create mode 100644 regression_tests/xmlin4/meta-mett.nhml create mode 100644 regression_tests/xmlin4/meta-metx-no-namespace.nhml create mode 100644 regression_tests/xmlin4/meta-metx.nhml create mode 100644 regression_tests/xmlin4/run_one_test.sh create mode 100644 regression_tests/xmlin4/run_tests.sh create mode 100644 regression_tests/xmlin4/second.xml create mode 100644 regression_tests/xmlin4/subt-sbtt-no-mime.nhml create mode 100644 regression_tests/xmlin4/subt-sbtt.nhml create mode 100644 regression_tests/xmlin4/subt-stpp-no-namespace.nhml create mode 100644 regression_tests/xmlin4/subt-stpp.nhml create mode 100644 regression_tests/xmlin4/text-stxt-header.nhml create mode 100644 regression_tests/xmlin4/text-stxt-no-mime.nhml create mode 100644 regression_tests/xmlin4/text-stxt.nhml create mode 100755 run_configure.sh create mode 100644 src/Makefile create mode 100644 src/bifs/arith_decoder.c create mode 100644 src/bifs/bifs_codec.c create mode 100644 src/bifs/bifs_node_tables.c create mode 100644 src/bifs/com_dec.c create mode 100644 src/bifs/com_enc.c create mode 100644 src/bifs/conditional.c create mode 100644 src/bifs/field_decode.c create mode 100644 src/bifs/field_encode.c create mode 100644 src/bifs/memory_decoder.c create mode 100644 src/bifs/predictive_mffield.c create mode 100644 src/bifs/quant.h create mode 100644 src/bifs/quantize.c create mode 100644 src/bifs/script.h create mode 100644 src/bifs/script_dec.c create mode 100644 src/bifs/script_enc.c create mode 100644 src/bifs/unquantize.c create mode 100644 src/compositor/audio_input.c create mode 100644 src/compositor/audio_mixer.c create mode 100644 src/compositor/audio_render.c create mode 100644 src/compositor/bindable.c create mode 100644 src/compositor/camera.c create mode 100644 src/compositor/compositor.c create mode 100644 src/compositor/compositor_2d.c create mode 100644 src/compositor/compositor_3d.c create mode 100644 src/compositor/compositor_node_init.c create mode 100644 src/compositor/drawable.c create mode 100644 src/compositor/drawable.h create mode 100644 src/compositor/events.c create mode 100644 src/compositor/font_engine.c create mode 100644 src/compositor/gl_inc.h create mode 100644 src/compositor/hardcoded_protos.c create mode 100644 src/compositor/hc_flash_shape.c create mode 100644 src/compositor/mesh.c create mode 100644 src/compositor/mesh_collide.c create mode 100644 src/compositor/mesh_tesselate.c create mode 100644 src/compositor/mpeg4_animstream.c create mode 100644 src/compositor/mpeg4_audio.c create mode 100644 src/compositor/mpeg4_background.c create mode 100644 src/compositor/mpeg4_background2d.c create mode 100644 src/compositor/mpeg4_bitmap.c create mode 100644 src/compositor/mpeg4_composite.c create mode 100644 src/compositor/mpeg4_form.c create mode 100644 src/compositor/mpeg4_geometry_2d.c create mode 100644 src/compositor/mpeg4_geometry_3d.c create mode 100644 src/compositor/mpeg4_geometry_ifs2d.c create mode 100644 src/compositor/mpeg4_geometry_ils2d.c create mode 100644 src/compositor/mpeg4_gradients.c create mode 100644 src/compositor/mpeg4_grouping.c create mode 100644 src/compositor/mpeg4_grouping.h create mode 100644 src/compositor/mpeg4_grouping_2d.c create mode 100644 src/compositor/mpeg4_grouping_3d.c create mode 100644 src/compositor/mpeg4_layer_2d.c create mode 100644 src/compositor/mpeg4_layer_3d.c create mode 100644 src/compositor/mpeg4_layout.c create mode 100644 src/compositor/mpeg4_lighting.c create mode 100644 src/compositor/mpeg4_path_layout.c create mode 100644 src/compositor/mpeg4_sensors.c create mode 100644 src/compositor/mpeg4_sound.c create mode 100644 src/compositor/mpeg4_text.c create mode 100644 src/compositor/mpeg4_textures.c create mode 100644 src/compositor/mpeg4_timesensor.c create mode 100644 src/compositor/mpeg4_viewport.c create mode 100644 src/compositor/navigate.c create mode 100644 src/compositor/nodes_stacks.h create mode 100644 src/compositor/offscreen_cache.c create mode 100644 src/compositor/offscreen_cache.h create mode 100644 src/compositor/svg_base.c create mode 100644 src/compositor/svg_filters.c create mode 100644 src/compositor/svg_font.c create mode 100644 src/compositor/svg_geometry.c create mode 100644 src/compositor/svg_grouping.c create mode 100644 src/compositor/svg_media.c create mode 100644 src/compositor/svg_paint_servers.c create mode 100644 src/compositor/svg_text.c create mode 100644 src/compositor/texturing.c create mode 100644 src/compositor/texturing.h create mode 100644 src/compositor/texturing_gl.c create mode 100644 src/compositor/visual_manager.c create mode 100644 src/compositor/visual_manager.h create mode 100644 src/compositor/visual_manager_2d.c create mode 100644 src/compositor/visual_manager_2d.h create mode 100644 src/compositor/visual_manager_2d_draw.c create mode 100644 src/compositor/visual_manager_3d.c create mode 100644 src/compositor/visual_manager_3d.h create mode 100644 src/compositor/visual_manager_3d_gl.c create mode 100644 src/compositor/x3d_geometry.c create mode 100644 src/dir_info create mode 100644 src/export.cpp create mode 100644 src/ietf/rtcp.c create mode 100644 src/ietf/rtp.c create mode 100644 src/ietf/rtp_depacketizer.c create mode 100644 src/ietf/rtp_packetizer.c create mode 100644 src/ietf/rtp_pck_3gpp.c create mode 100644 src/ietf/rtp_pck_mpeg12.c create mode 100644 src/ietf/rtp_pck_mpeg4.c create mode 100644 src/ietf/rtp_streamer.c create mode 100644 src/ietf/rtsp_command.c create mode 100644 src/ietf/rtsp_common.c create mode 100644 src/ietf/rtsp_response.c create mode 100644 src/ietf/rtsp_session.c create mode 100644 src/ietf/sdp.c create mode 100644 src/isomedia/avc_ext.c create mode 100644 src/isomedia/box_code_3gpp.c create mode 100644 src/isomedia/box_code_adobe.c create mode 100644 src/isomedia/box_code_apple.c create mode 100644 src/isomedia/box_code_base.c create mode 100644 src/isomedia/box_code_drm.c create mode 100644 src/isomedia/box_code_meta.c create mode 100644 src/isomedia/box_dump.c create mode 100644 src/isomedia/box_funcs.c create mode 100644 src/isomedia/data_map.c create mode 100644 src/isomedia/drm_sample.c create mode 100644 src/isomedia/hint_track.c create mode 100644 src/isomedia/hinting.c create mode 100644 src/isomedia/isom_intern.c create mode 100644 src/isomedia/isom_read.c create mode 100644 src/isomedia/isom_store.c create mode 100644 src/isomedia/isom_write.c create mode 100644 src/isomedia/media.c create mode 100644 src/isomedia/media_odf.c create mode 100644 src/isomedia/meta.c create mode 100644 src/isomedia/movie_fragments.c create mode 100644 src/isomedia/sample_descs.c create mode 100644 src/isomedia/stbl_read.c create mode 100644 src/isomedia/stbl_write.c create mode 100644 src/isomedia/track.c create mode 100644 src/isomedia/ttml.c create mode 100644 src/isomedia/tx3g.c create mode 100644 src/laser/lsr_dec.c create mode 100644 src/laser/lsr_enc.c create mode 100644 src/laser/lsr_tables.c create mode 100644 src/mcrypt/cbc.c create mode 100644 src/mcrypt/cfb.c create mode 100644 src/mcrypt/ctr.c create mode 100644 src/mcrypt/des.c create mode 100644 src/mcrypt/ecb.c create mode 100644 src/mcrypt/g_crypt.c create mode 100644 src/mcrypt/ncfb.c create mode 100644 src/mcrypt/nofb.c create mode 100644 src/mcrypt/ofb.c create mode 100644 src/mcrypt/rijndael-128.c create mode 100644 src/mcrypt/rijndael-192.c create mode 100644 src/mcrypt/rijndael-256.c create mode 100644 src/mcrypt/stream.c create mode 100644 src/mcrypt/tripledes.c create mode 100644 src/media_tools/ait.c create mode 100644 src/media_tools/av_parsers.c create mode 100644 src/media_tools/avilib.c create mode 100644 src/media_tools/dash_client.c create mode 100644 src/media_tools/dash_segmenter.c create mode 100644 src/media_tools/dsmcc.c create mode 100644 src/media_tools/dvb_mpe.c create mode 100644 src/media_tools/filestreamer.c create mode 100644 src/media_tools/gpac_ogg.c create mode 100644 src/media_tools/html5_media.c create mode 100644 src/media_tools/html5_mse.c create mode 100644 src/media_tools/img.c create mode 100644 src/media_tools/ismacryp.c create mode 100644 src/media_tools/isom_hinter.c create mode 100644 src/media_tools/isom_tools.c create mode 100644 src/media_tools/m2ts_mux.c create mode 100644 src/media_tools/m3u8.c create mode 100644 src/media_tools/media_export.c create mode 100644 src/media_tools/media_import.c create mode 100644 src/media_tools/mpd.c create mode 100644 src/media_tools/mpeg2_ps.c create mode 100644 src/media_tools/mpeg2_ps.h create mode 100644 src/media_tools/mpegts.c create mode 100644 src/media_tools/reedsolomon.c create mode 100644 src/media_tools/saf.c create mode 100644 src/media_tools/text_import.c create mode 100644 src/media_tools/vobsub.c create mode 100644 src/media_tools/webvtt.c create mode 100644 src/odf/desc_private.c create mode 100644 src/odf/descriptors.c create mode 100644 src/odf/ipmpx_code.c create mode 100644 src/odf/ipmpx_dump.c create mode 100644 src/odf/ipmpx_parse.c create mode 100644 src/odf/oci_codec.c create mode 100644 src/odf/odf_code.c create mode 100644 src/odf/odf_codec.c create mode 100644 src/odf/odf_command.c create mode 100644 src/odf/odf_dump.c create mode 100644 src/odf/odf_parse.c create mode 100644 src/odf/qos.c create mode 100644 src/odf/slc.c create mode 100644 src/scene_manager/encode_isom.c create mode 100644 src/scene_manager/loader_bt.c create mode 100644 src/scene_manager/loader_isom.c create mode 100644 src/scene_manager/loader_qt.c create mode 100644 src/scene_manager/loader_svg.c create mode 100644 src/scene_manager/loader_xmt.c create mode 100644 src/scene_manager/scene_dump.c create mode 100644 src/scene_manager/scene_engine.c create mode 100644 src/scene_manager/scene_manager.c create mode 100644 src/scene_manager/scene_stats.c create mode 100644 src/scene_manager/swf_bifs.c create mode 100644 src/scene_manager/swf_parse.c create mode 100644 src/scene_manager/swf_svg.c create mode 100644 src/scene_manager/text_to_bifs.c create mode 100644 src/scenegraph/base_scenegraph.c create mode 100644 src/scenegraph/commands.c create mode 100644 src/scenegraph/dom_events.c create mode 100644 src/scenegraph/dom_smjs.c create mode 100644 src/scenegraph/html5_media_smjs.c create mode 100644 src/scenegraph/html5_mse_smjs.c create mode 100644 src/scenegraph/mpeg4_animators.c create mode 100644 src/scenegraph/mpeg4_nodes.c create mode 100644 src/scenegraph/mpeg4_valuator.c create mode 100644 src/scenegraph/smil_anim.c create mode 100644 src/scenegraph/smil_timing.c create mode 100644 src/scenegraph/svg_attributes.c create mode 100644 src/scenegraph/svg_properties.c create mode 100644 src/scenegraph/svg_smjs.c create mode 100644 src/scenegraph/svg_types.c create mode 100644 src/scenegraph/vrml_interpolators.c create mode 100644 src/scenegraph/vrml_proto.c create mode 100644 src/scenegraph/vrml_route.c create mode 100644 src/scenegraph/vrml_script.c create mode 100644 src/scenegraph/vrml_smjs.c create mode 100644 src/scenegraph/vrml_tools.c create mode 100644 src/scenegraph/webvtt_smjs.c create mode 100644 src/scenegraph/x3d_nodes.c create mode 100644 src/scenegraph/xbl_process.c create mode 100644 src/scenegraph/xml_ns.c create mode 100644 src/terminal/channel.c create mode 100644 src/terminal/clock.c create mode 100644 src/terminal/decoder.c create mode 100644 src/terminal/input_sensor.c create mode 100644 src/terminal/input_sensor.h create mode 100644 src/terminal/media_control.c create mode 100644 src/terminal/media_control.h create mode 100644 src/terminal/media_manager.c create mode 100644 src/terminal/media_memory.c create mode 100644 src/terminal/media_memory.h create mode 100644 src/terminal/media_object.c create mode 100644 src/terminal/media_sensor.c create mode 100644 src/terminal/mpeg4_inline.c create mode 100644 src/terminal/network_service.c create mode 100644 src/terminal/object_browser.c create mode 100644 src/terminal/object_manager.c create mode 100644 src/terminal/scene.c create mode 100644 src/terminal/svg_external.c create mode 100644 src/terminal/term_node_init.c create mode 100644 src/terminal/terminal.c create mode 100644 src/utils/alloc.c create mode 100644 src/utils/base_encoding.c create mode 100644 src/utils/bitstream.c create mode 100644 src/utils/cache.c create mode 100644 src/utils/color.c create mode 100644 src/utils/configfile.c create mode 100644 src/utils/dlmalloc.c create mode 100644 src/utils/downloader.c create mode 100644 src/utils/error.c create mode 100644 src/utils/gzio.cpp create mode 100644 src/utils/list.c create mode 100644 src/utils/map.c create mode 100644 src/utils/math.c create mode 100644 src/utils/module.c create mode 100644 src/utils/module_wrap.h create mode 100644 src/utils/os_config_init.c create mode 100644 src/utils/os_divers.c create mode 100644 src/utils/os_file.c create mode 100644 src/utils/os_module.c create mode 100644 src/utils/os_net.c create mode 100644 src/utils/os_thread.c create mode 100644 src/utils/path2d.c create mode 100644 src/utils/path2d_stroker.c create mode 100644 src/utils/ringbuffer.c create mode 100644 src/utils/sha1.c create mode 100644 src/utils/symbian_net.cpp create mode 100644 src/utils/symbian_os.cpp create mode 100644 src/utils/token.c create mode 100644 src/utils/uni_bidi.c create mode 100644 src/utils/unicode.c create mode 100644 src/utils/url.c create mode 100644 src/utils/utf.c create mode 100644 src/utils/xml_parser.c create mode 100644 src/utils/zlib_symbian_ext.h create mode 100644 src/utils/zutil.c create mode 100644 src/utils/zutil.h create mode 100644 version.bat diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f8c796f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,19 @@ +* text=auto + +*.c text +*.cpp text +*.h text +*.ttx text +Makefile text + +#unix +*.sh text eol=lf +configure text eol=lf + +#windows +*.bat text eol=crlf +*.sln text eol=crlf +*.vcproj text eol=crlf +*.vcxproj text eol=crlf +*.dsp text eol=crlf +*.dsw text eol=crlf diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1f2675f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +language: c +compiler: gcc +before_install: + - sudo apt-get update -qq +install: + - sudo apt-get install build-essential fakeroot dpkg-dev devscripts ccache debhelper pkg-config g++ + - sudo apt-get install -y zlib1g-dev libfreetype6-dev libjpeg62-dev libpng12-dev libopenjpeg-dev libmad0-dev libfaad-dev libogg-dev libvorbis-dev libtheora-dev liba52-0.7.4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libxv-dev x11proto-video-dev libgl1-mesa-dev x11proto-gl-dev linux-sound-base libxvidcore-dev libssl-dev libjack-dev libasound2-dev libpulse-dev libsdl1.2-dev dvb-apps libavcodec-extra-53 libavdevice-dev libmozjs185-dev + - sudo apt-get install -y gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev +env: + - GPAC_CONFIGURE_PREFIX="--prefix=build/all" GPAC_CONFIGURE_OPTIONS="" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" + - GPAC_CONFIGURE_PREFIX="--prefix=build/disable-all" GPAC_CONFIGURE_OPTIONS="--disable-all" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" + - GPAC_CONFIGURE_PREFIX="--prefix=build/static-mp4box" GPAC_CONFIGURE_OPTIONS="--static-mp4box" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" + - GPAC_CONFIGURE_PREFIX="--prefix=build/static-modules" GPAC_CONFIGURE_OPTIONS="--static-modules" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" + - GPAC_CONFIGURE_PREFIX="--prefix=build/disable-manual" GPAC_CONFIGURE_OPTIONS="--use-js=no --use-mad=no --use-xvid=no --use-ogg=no --use-vorbis=no --use-theora=no --use-openjpeg=no --disable-streaming --disable-isoff-frag --disable-isoff-hint --disable-isoff-write --disable-loader-xmt --disable-loader-bt --disable-loader-isoff --disable-scene-encode --disable-mcrypt --disable-od-dump --disable-scene-dump --disable-scene-stats --disable-swf --disable-export --disable-import --disable-m2ps --disable-ogg -disable-avi --disable-qtvr --disable-seng --disable-smgr --disable-x3d --disable-3d --disable-ssl --disable-jack --disable-pulse --use-a52=no --disable-odf --disable-isoff --disable-m2ts-mux --disable-dvbx --disable-saf --disable-vobsub --disable-ttxt --disable-od-parse" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" TARGET="" + - GPAC_CONFIGURE_PREFIX="--prefix=build/i686-w64-mingw32" GPAC_CONFIGURE_OPTIONS="--static-mp4box --use-zlib=no" GPAC_CONFIGURE_ECFLAGS="-Ibuild/i686-w64-mingw32/include -w -fPIC" GPAC_CONFIGURE_ELDFLAGS="-Lbuild/i686-w64-mingw32/lib" GPAC_CONFIGURE_CROSS="--target-os=mingw32 --cross-prefix=i686-w64-mingw32-" TARGET="" + - GPAC_CONFIGURE_PREFIX="--prefix=build/x86_64-w64-mingw32" GPAC_CONFIGURE_OPTIONS="--static-mp4box --use-zlib=no" GPAC_CONFIGURE_ECFLAGS="-Ibuild/x86_64-w64-mingw32/include -w -fPIC" GPAC_CONFIGURE_ELDFLAGS="-Lbuild/x86_64-w64-mingw32/lib" GPAC_CONFIGURE_CROSS="--target-os=mingw32 --cross-prefix=x86_64-w64-mingw32-" TARGET="" + +script: + - ./configure $GPAC_CONFIGURE_PREFIX $GPAC_CONFIGURE_OPTIONS --extra-cflags="$GPAC_CONFIGURE_ECFLAGS" --extra-ldflags="$GPAC_CONFIGURE_ELDFLAGS" && make clean && make $TARGET && make install diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..107c2c5 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,11 @@ +Author: +======= +Jean Le Feuvre + +Contributors: +============= +Cyril Concolato contributing SVG, SMIL, ISMACryp MP4 support and V4Studio (together with some ENST people) + + +Pierre Souchay for PulseAudio and JACK audio support +Ivan Vecera () for VobSub support diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..9402234 --- /dev/null +++ b/BUGS @@ -0,0 +1,9 @@ +BUGS + +A bug tracker is available at http://sourceforge.net/projects/gpac/ +BUG REPORTS + +If you find a bug that is not in the list above, please report it at + +http://sourceforge.net/tracker/?group_id=84101&atid=571738 + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..223ede7 --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/Changelog b/Changelog new file mode 100644 index 0000000..78660d9 --- /dev/null +++ b/Changelog @@ -0,0 +1,732 @@ +Full Changelog is available here: +https://sourceforge.net/apps/trac/gpac/log/ + +25/05/2012: GPAC 0.5.0 + - MPEG-DASH and Apple HLS support in GPAC Clients + - MPEG-DASH segmenter for ISO files and MPEG-2 TS in MP4Box + - MP42TS generator now supports HLS output + - Support for MPEG-U and W3C widgets + - UPnP and DLNA support in the player through Platinum libraries, interfaced in JavaScript + - Better support for AVC and SVC muxing in MP4 + - Support for OpenSVC decoder + - Stereo and Multi-view renderer for auto-stereoscopic screens + - iOS and Android support (but Symbian support has been dropped) + - Camera input through "camera://default" URLs on Windows, OSX 32bit, Linux V4L v1 and Android + - experimental audio filters + - Better T-DMB support + - experimental DVB-MPE and DSM-CC support + - BIFS ExtendedCore2D profile support + - more work on GUI + - and many many fixes and improvements in players and MP4Box + +02/12/08: GPAC 0.4.5 + - Support for AC3 in ISO Media, AC3 decoder (liba52) RTP hinting + - Support for MediaAccessEvent (spec still under development ??) + - Added support for user extensions (global class only) in JS through modules - cf gpac_js for sample code. + - Initial support for 3GPP DIMS (file creation and dumping + playback) + * Currently only SVG as overlay is supported for DIMS files, we are not sure about the specification on this topic + * RTP hinting /playback is not supported yet + - Support for SVG foreignObject - all GPAC supported content can be played in a foreign object + - Added automatic switch between 2D and 3D context for VRML/BIFS Inline node + - Basic support for DCCI queries: + * the DCCI object is exposed in scripts as 'DCCIRoot' + * the related document can be specified in GPAC configuration file in the [General] section with the 'EnvironmentFile' key + pointing to an XML file to use as the ontology context + * DCCI's propertyFilters are NOT supported yet. + - Added support for YCbCr OpenGL texturing (only tested with GL_MESA_ycbcr_texture) + - Fixed bugs in OSS audio (100% CPU usage when no audio to play) and ALSA (broken playback) + - Initial support for YUV overlays on Win32 and Linux (Needs XVideo) + * only one overlay at the moment + * Vector graphics /images can be drawn above the overlay if the video output supports dest color keying + - Changed 3D mesh object to be slightly more compact (colors and normal) + - Unified focus model for SVG and MPEG-4. MPEG-4 focus can only be used through tab/-tab (no north/east/.. navigation) + * The MPEG-4 focus is based on the groups (2D/3D) presenting interactive features (sensors) + * keyboard mapping for sensors is: + isOver triggered when focus moves in(isOver=TRUE) and out (isOver=FALSE) + isActive triggered when ENTER key is pressed (isActive=TRUE) and released (isActive=TRUE) + direction keys with or without SHIFT to simulate mouse move + * Layout node is considered as a sensor when scroll_rate is 0, so that the user can scroll the layout + * The focus is by default on the UA (GPAC), not on the content. + - Added support for inplace text edition in SVGT and in MPEG4 + * support for clipboard paste at current caret pos (win32, wxWidgets - no WinCE/symbian yet) + * VRML/MPEG4/X3D: this is not standard, enabled with "EDITABLE" present in text->fontStyle->styles. + Added because StringSensor does not allow for in-place editing of the string + - Added support for text selection in MPEG4 (non standard) / SVGT with clipboard copy (win32, wxWidgets - no copy for text+tspan - no WinCE/symbian yet) + - Better support for SVG , added support for SVG->svg linking (ElementID and svgView) and many svg fixes + - Added support for MPEG-4 over MPEG-2 TS in mp42ts (MPEG-4 SL in MPEG-2 PES) + - Added support for MPEG-4 AAC/LOAS/LATM/ over MPEG-2 TS for import in ISO Media and in the player. + Only basic DVB config is supported for LATM + - Fixed support for AVC/H264 over MPEG-2 TS import in ISO Media and in the player. Only one PPS/SPS is allowed + - Added support for offscreen GL rendering on symbian using PBuffers + - SVG fonts should now be quite stable, but does not support kerning + - Moved all Font modules to the new glyph-based architecture + - Moved SVG text to new glyph-based renderer, added support for OpenGL drawing and textured mode + - Added support for AVC/H264 in mp4_streamer + - Added support of MPEG-4 systems over MPEG-2 + - Added extended version of "-node" switch in MP4Box, to get the list of possible nodes. For insatnce, "MP4Box -node Anchor.children" + - New glyph-based font manager + - Misc fixes in SVG rendering with OpenGL + - Renderer modules have been removed from GPAC. The new integrated 2D+3D renderer has been moved to libgpac and is now + called "compositor". Some renaming has been done in the process to clarify a bit some functions. + NOTE: EVC3 and MSVC8 projects have not been updated yet + - added support for TrackSelection (tsel) - (c) 2007 ENST & RresonateMP4 - cf MP4Box -h general + - added support for PASP in ISO files + - misc fixes in render_full module + - committed patch fixing VobSub extraction bug + - added support for http playback in ffmpeg demuxer + +31/05/07: GPAC 0.4.4 + - Added support for XMLHttpRequest for both VRML/MPEG-4 and SVG. All methods should be supported, but only GET/HEAD have been tested + - Added a basic subset of DOM Core for xml doc (XMLHttpRequest, SVG) and moved the uDOM implementation in it. + - Added support for SVG focus & navigation in 2D renderer + - new SVG scene graph implementation with much lower memory usage + - Updated LASeR to new SVG implementation and fixed many bugs in codec + current LASeR binary version should now be in sync with the latest spec (IS+COR, AMD still to be done) + - Added support for some LASeR tools: + - conditional + - clipBegin/clipEnd and syncReference on audio/video elements + - WARNING: + * other LASeR (non-SVG) v1 elements and all v2 elements are NOT supported + * LASeR save/restore and sendEvents are NOT supported + * SAF handling is likely not conformant yet + - Moved default SVG implementation to dynamic attribute allocation + - ALSA output module + - DVB support for Linux - connection URL is dvb://ChannelName, cf doc/configuration.html + - Moved ISMA decryption to run-time module for basic DRM tests + - Added support for NAT Keep Alive (RTP streaming only) + - Two new test apps: + mp4_streamer: RTP unicaster/mulitcaster + mp42ts: MPEG-2 TS sample gateway, can output to file or to RTP. Supports ISO file and SDPs (RTP only, no RTSP) as input. + - Changed default behavior in MP4Box when adding AAC-SBR with explicit signaling: full SBR Samplerate is now used in media track. + - Added JP2 and MJP2 support for mux/demux and playback - latest version of openjpeg (1.1) used for decoding (Win32 only). + Win32 user: if you don't want to install openjpeg, remove GPAC_HAS_JP2 from img_in project settings + - large code rewrite in scenegraph and 2D renderer to lower memory usage + - added support for OMA DRM2 packaging in MP4Box (doc to come) + - Symbian OS now supported. Build instructions are in doc/INSTALL.symbian. Network is NOT working on symbian yet + - Major speed improvement of XML SAX parser + - added unthreaded mode in MP4Client (-no-thread switch) to test behavior on symbian + - added fullscreen startup mode in MP4Client (-fs switch) + - better handling of iTunes tags in MP4Box (set/get) and in players (title display) + - added support for multiple RTSP sessions in an SDP description + - added support for faked broadcast mode in SDP (forbids any timeline control by player except initial play/final stop) + syntax is (in media SDP section, per stream): a=gpac-broadcast:1 + - added ffmpeg support for WinCE devices (ffmpeg for WinCE is available in gpac_extra_libs) + - added GPAC log system + + - moved key/mouse event subsystem to DOM3 model + - Fixed handling of QT V1 and V2 audio descriptions + - Misc source code reorganization for RTP (depacketizers now in libgpac, no longer in plugins) + - Fixed support for IPV6 and for multicast (IPV4 and IPV6). Some issues remain with IPV6 on Win32 XP, so IPV6 is disabled by default on Win32 + - Fixed handling of negative delays when adding/appending media tracks with MP4Box + - moved ffmpeg headers to latest CVS version (05/01/2007). + - fixes in MPEG2 TS import and demuxer + - added detection of FPS for raw AVC import when present + - fixed a display freezing bug in osmo4 for PocketPC 2003. + - added support for svg animation and svg use with external resources + - cleanup of MPEG-4 RemoteOD + support for segment identifiers at scene level + - some workarounds for iPod file producing (special UUID needed) (-ipod option, auto on for .m4a and .m4v extensions) + - added windowless mode on Win32: transparent background color is defined in the config file ( [Rendering] ColorKey ) + - major speed improvements in MPEG-4/VRML scripts and SVG uDOM regarding node creation + - and a lot more bug fixes... + +21/07/06: GPAC 0.4.2 + - commit of GPAX (GPAC ActiveX) - controller only works in IE and ActiveX control tester for now. + - API changes to Osmozilla to keep in sync with GPAX. Sample html file can be found in applications/GPAX. + - both plugin now support browser navigation (ie link to html within MPEG-4 content) + - Plugins can be used to modify the presentation from a parent HTML doc + - check sample files in regression tests for more details + - iTune tagging support, (patch from Andrew Voznytsa with slight modif). Tagging can be done with MP4Box -itags option. The tags are passed in a single string, separated by ':', formatted as 'tag_name=tag_value'. Supported tags names are: album, artist, comment, compilation, composer, created, disk, encoder, genre, name, tempo, track, tracknum, writer. + NOTE: to make sure you mp4 is importable on an iPod, you must: + - use .m4a extension + - specify the right brands: MP4Box -brand "M4A " -ab mp42 + This process is automated in MP4Box for all file with extension .m4a + - added MPEG-1/2 raw importing (extensions: .m1v and .m2v). + - cleanup of all Makefiles: + no more recursive makes for libgpac + gpac can now be compiled outside the main source tree with gcc, eg $ ~/cvs/test>../gpac/configure + - Support for VobSub import and export (.idx) thanks to a great patch from Falco ! + - initial version of MPEG-2 TS demuxer (MP4Box and client plugin) + program-based import for MPEG-2 TS streams (MP4Box -add file.ts#program=ProgName). + - initial IPV6 support + - MP42AVI is now deprecated. MP4Client can now be used to produce uncompressed bmp/raw/AVI, dumping the complete presentattion rather than just BIFS scenes (audio is currently not extracted). Usage: + MP4Client -bmp 1-2.5-3 file.mp4 take screenshots of file.mp4 aty T=1, 2.5 and 3 seconds + MP4Client -avi -fps 15.0 -size 176x144 file.mp4 produces an uncompressed AVI of resolution 176x144, framerate 15 + MP4Client -avi 4-10 file.mp4 produces an uncompressed AVI of the scene between 4 and 10 seconds + Check MP4Client man page for more details. + - added support for major brand versioning in MP4Box: "-brand GPAC:2" will set the major brand to GPAC, with a version of 2. + - regression tests (.bt and .x3dv) are now part of GPAC source tree + changed all audio and video media in regression tests. + - added 2D/3D selection param for osmozilla: use3d="true" or use3d="false" to force renderer used. + - added support for importing AMR/SMV/EVRC file missing their magic number + - moved all language handling to both ISO 639-1 (2 char code) and 639-2 (3 char code), as 639-1 is used in SVG. + - removed old XML parser, all parsing now relies on a new GPAC SAX parser (avoid dependency on libxml when unneeded). + - support for progressive loading support for XMT and X3D files. + - new svg_in module using gpac sax parser (supports progressive loading too) + - cf configuration.html or man gpac for more info on progressive loading control + - added 'define' support in BT - to use it just do: + #define symbol blab labl a + and reuse the symbol in the BT text. This may be quite buggy, but it can be usefull + - support for Scene Carousel in hinters, core and rtp reassembler. Currently only BIFS and BIFS+AV can be use the scene carousel, carouseling of + static data (eg images) is not supported. The OD data must be embedded in the IOD a la ISMA. + - added FPS and size info dumping for MPEG and AVI file import (MP4Box -info file.mpg) + - improved 3D renderer while checking the X3D conformance suite + - changed MPEG-4 SP -> AVI to add VOSH before each I-frame + - Experimental support for LASeR (encoder, decoder and decoder module). + - Far from behing complete or usable at this time, binary syntax not 100% safe and COR to standard is in edition stage... + - LASeR RAP generation in MP4Box + - added SAF (LASeR Simple Aggregation Format) support: mux and demux (MP4Box) + SAF input plugin. + Basic LASeR usage: + encoding: MP4Box -mp4 file.svg, MP4Box -saf file.svg + decoding: MP4Box -svg file.mp4, MP4Box -xsr file.mp4 (dumps to LASeRML format) + - added patch from FT R&D for simple anim mask encoding needed for FAP/BAP streams on FDT/BDP nodes. + - added patch for drift-controled interleaving (interleaves while trying to keep chunk synchronized). This is now the storage mode of MP4Box, old interleaving is possible with -old-inter option. + - added support for tight interleaving without hinting in MP4Box. + - added support for delayed concatenation (-cat file.mp4:delay=2000 test.mp4) + - added "-name" option to MP4Box (track import and general cmd line opt) for setting the track handler name + - More SVG improvements and features: + - support for SVG scripting (ecmascript through SpiderMonkey) - a good subset of microDOM is supported (!! presentation traits are missing). + - support for SVG events (DOM) + - support for SVG scene dumping + - SVG Tiny 1.2 gradients + gradient matrix (1.1 feature) + - SVG.preserveAspectRatio support + - system color paint + - basic conditional processing (switch) + - SMIL anim events (begin, end, restart) + - added PAR modification support to MP4Box (import time and file based) + - improved precision of IsoMedia file spliting + - added NHML import/export. NHML is an XML representation of the NHNT file, with add-ons and a more flexible way of integrating media. Doc to come on web site + - clean-up of 2D direct rendering mode: + * no more bounds tracking for less memory usage + * automatically mode switch to direct rendering when using slide navigation (pan&zoom) + - clean-up of soft raster: + * removed all bezier curbs handling, let gpac core handle those + * paths are now always flatten to reduce rastering times + * misc optimizations of scanline converter (no more Y-sorting, only X-sorting used) + - speed improvements in BT/WRL loader + - updated makefiles for compilation under GPE + - made FreeType plugin log unknown fonts in general cfg file to speed up font selection. + - changed module naming - all modules are now prefixed with "gm_", and module is loaded/unloaded at run-time + - changed isomedia file open API for better support of temporary directories + - simplified 2D blitter for non DirectX output: no more in-middle surface used, direct stretch, blit and yuv conversion to back buffer + - added software and hardware support for MaterialKey in 2D renderer + - Support for SP2003 and PPC2003 + - added all project files for evc4 + - added osmophone to gpac/applications, demo player for Smartphone devices (tested on SPV C500 and PocketPC) + - support for GDI drawing on WinCE to avoid weird menu behaviour in windowed mode + - added support for OpenGL-ES in 3D renderer, in DX and in GAPI plugins + * tested with Hybrid Graphics and Vincent3D implementations + * Klimt could compile but no decent results + * Result tested on PocketPC/SmartPhone 2003 and regular windows + - added LASeR XML to SVG loader + - improved SRT -> 3GPP convertion - now accepts any number of , , tags at random places. + + - fixed AVC/H264 parsing (pic size detection on interleaved stream and cropping were broken) + - fixes on X3D scene parsing and dumping + - fixed mp4 root OD creating when fragmenting file (PLs were not copied over) + - fixed bug in large MP4 file (> 4GB) writing (chunk offset table was corrupted) + - fixes in InputSensor handling. + - fixes in XMT proto+script parsing + - fixed ISOMedia track duration in case of ctts table + - fixed PAR issus at import time setting wrong track sizes for visual media. + - fixed handling of 64-bit timing in GPAC (clients and MP4Box). Impacts on a few APIs (libisomedia, scene manager and terminal). + - fixed bugs in BIFS RAP generation (BT and XMT-A loaders) + - fixed support for node insert and delete in laser + - fixed AVC import bug with multiple PPSs per stream + - fixed stts bug in file concatenation (first inserted sample had a wrong duration) + - fixed v5 and v7 MPEG-4 node templates + - fixed ttxt extraction (fontID was missing in styles) + - fixed MP4Box -add file1 -cat file2 use case (broken CTTS compute) + - fixed 3GP brand when using AVC (3GP6 shall be used) + - fixed misc issues with text import/info display on track sizes and 3GP text track importing. + - fixed bug in gradient raster (spread/pad/repeat modes were broken) + - fixed bevel stroking bug and many SVG rendering ones + - fixed bug in MP4Box track concatenation of MPEG-4 user streams + - fixed bug in meta items storage (existing items were corrupted on file rewrite) + - fixed splitx option to support end times larger than file duration + - fixed globalQP context loading issues + - fixed display bug when switching between MPEG-4 and SVG scenes + - fixed absolute URLs handling on WinCE devices + - fixed redraw bug in 2D renderer for simple video drawing (background was always repaint regardless of video transparency) + - fixed UTF8 vs Win-CP text handling (BT and XMT parsers, subs->bifs and subs->ttxt converters) + - fixed bug in unknown stsd boxes handling + - fixes for gpac compilation on 64 bits platforms + - fixed bugs related to cache in file downloader + +03/08/05: GPAC 0.4.0 RC2 + - fixed Invalid versioning of previous release (was still 0.4.0-DEV...) + - fixed MinGW compilation + - fixed MP4Box handling of full MSDOS paths (C:\) + - fixed GCC 4 compilation issues + - added MacOS X (DARWIN) compilation patches + - fixed OSS audio compilation (seems to perform perfectly on 50% of systems tested and dramatically fail on the rest...) + - fixed MP4A-LATM support at client side + - fixed X11 module in embedded mode (should work well with both Osmo4/wx and Osmozilla) + +28/07/05: GPAC 0.4.0 release + ** GPAC is now licensed under LGPL. ** + Massive code rewrite and repository reorganization in order to comply to some base coding style (cf gpac/doc/CODING_STYLE) have taken place + since previous release. Documentation is still a work in progress. + APIs are not backward compatible, but should now be in a frozen state/spelling for the most common tools (utils, MPEG-4 OD, IsoMedia and terminal APIs) + + - Fixed FAAD multichannel support with latest FAAD CVS version (bug due to FAAD inner channel creation). Latest version should + support both multichannel and AAC radios. + - added support for normal drawing (for debug purposes) in 3D renderer + - adedd support for single instance of Osmo4/w32 + - changed audio configuration options to "Number of buffers" and "TotalDuration" + - fixed old bug in audio renderer screwing up the audio from time to time + - moved ffmpeg to latest CVS version (25/07/05). THIS VERSION IS NO LONGER COMPATIBLE with previous ones used in GPAC, update + your binaries!! Also updated ffmpeg plugin to new ffmpeg API + - moved all fullscreen handling to dedicated windows, refinement of wxOsmo4. + - more work on x11 plugin (events handling, 3D support) - THIS IS EXPERIMENTAL AT THIS RELEASE LEVEL, CHECKOUT CVS FOR BETTER SUPPORT... + - fixed anamorphic video handling in GPAC, both playing (2D and 3D) and MP4Box parsers (only done for MPEG-4 Visual, not AVC). Video is + now only rescaled at blit time + - changed ';' separators to ':' seprators in MP4Box (meta options and track import options) for linux prompt compatibility. + - misc fixes in tx3g track import, tx3g bt dump and couple of issues introduced in 0.3.0->0.4.0 migration + - misc cleanup of GF_VideoOutput interface. + - started doc manager using doxygen (doxyfile added in gpac/doc). APIs may be slightly reworked during the documentation phase. + Documentation will only be produced for libgpac, eg all exported headers in gpac/include/gpac + Development APIs documentation (gpac/include/gpac/internal) will come later. + - cleaned up IsoMedia reading for more efficient and more reliable parsing + - misc fixes in MP4Box option parsing, in RTP multicast setup + - Osmozilla should now be much more stable on Win32 - Linux version to come. + + +20/06/05: GPAC 0.3.0 release + - fixed bug in 4GB file writing in interleaving mode + - fixed bug in absolute path usage in MP4Box + - added -cat file*.mpg syntax support + - added support for mass encryption in ISMACrypt drm_file (trackID="*" means all tracks get encrypted with the desired key) + - fixed compilation of wxOsmo4 with wxWidgets+Unicode + - fixed bug in 3GPP text layout when not fully contained in video + - added mapping between OD.ESD.GF_Language and MP4.MediaHeader.Language (BT/XMT <-> MP4) + - fixed bug in SDP playback without RTSP session attached (live casts) + - added language and delay selection at import time (cf MP4Box -h import) + - made -lang able to change all tracks languages by default !erase language specified at import time! + - added -lang option to MP4Box to change track language + - added -delay option to MP4Box to change initil media delay - ALTHOUGH 100% STANDARD, THIS MAY NOT BE SUPPORTED BY SOME PLAYERS + - updated configure for opengl disabling and fixed-point configuration + - misc fixes in ffmpeg decoder and MP4Box ISMA for PAR - this is disabled by default due to some unsolved crashes, cf gpac/doc/configuration.html or man gpac.s + - misc updates in MP4Box meta handling for item extraction. + - fixed MPEG-2 aac importing and info dumping + - fixed 3GPP text display bug when stoping and changing an animationStream using a 3GPP text object. + - fixed AVC/H264 HP parsing + - added BIFS track visual size info at BT/XMT encoding stage + - MOVED FFMPEG INCLUDE FILES TO LATEST CVS VERSION to support AVC/H264 HP decoding + - added meta self reference item for dual-headed files + - commit MPEG-4 LATM Audio hinting patch and added rtp aggregation. RTP reassembler NOT UPDATED YET + - fixed bugs in TeXML parser + - fixed bt/xmt to MP4 encoding for IOD with single BIFS ESD.URLString set + - fixed SVG outline handling and SVG/SMIL anim on appearance/geometry + - fixed svg_loader compilation on winCE (ARM binaries and include to follow in next release of gpac_extra_libs) + - commit of SVG fixed-point version + - Fixed MP4Box spliter crash introduced by MetaBox support. + - Merged MP21 and MP4 handling, added meta support in MP4Box (creation/extraction - cf MP4Box -h meta) + + FROM THIS DAY ON, ALL WORK ADDED TO GPAC IS COPYLEFT ENST + +15/05/05: + - Updated makefiles and configure for MacOSX support + - commit of GPAC fixed-point version - may not be completely stable yet :) + - changed all project files location for soon-to-come EVC4 and Visual .NET support + - changed 2D path object to directly support cubic and quadratic bezier (outliner do support them too), inspired from FreeType. + - MSVC Users: moved to wxWidgets 2.6.0 !! + - more fixes on CTTS in H264/AVC importer (p-frame reorder and some I/B sequences with neg POC) + - fixed last sample duration in mp4 for BIFS/OD/Text + - completely rewrote AVC CTS computing to handle b-refs properly + - fixed improper instanciation of externProto with VRML files not declaring default field values in externProtos + - reworked file splitter to support duration and size based splittings + - fixes in file concatanation + - support for "self" parameter in Anchor to replace only inline scenes on anchors + - fixed H263 raw importer (frame boundary detection and frame size) - changed default H263 frame rate to 15 fps (more used than 25 in 3GP). + - added support for new chaper format: CHAPTERX=HH:MM:SS[:ms or .ms] and CHAPTERXNAME=string + - committed AVC parser patch from bobolobo (SEI parsing and recovery points) + - added support for nero chapters in MP4 ('chpl' box), in MP4Box (-chap file.chp) and selection in players (chapters mapped to MPEG-4 SegmentDescriptors). + note regarding chp files: not sure about file syntax, currently support for (one chapter entry per line): + ZoomPlayer syntax: AddChapter (-fps for import framerate selection), AddChapterBySecond and AddChapterByTime + Regular time code … la SRT: HH:MM:SS[:ms or .ms] [Chapter Name] + SMPTE time code: HH:MM:SS;fr/fps [Chapter Name] - if fps is omitted, use '-fps' if specified or 25 fps default. + + - fixed avi packed bitstream flag removal bug with beta versions of DivX. + - fixed bugs in AVC CTTS compute + - wxOsmo4 now single-windowed on win32 with DirectX output driver (SDL one buggy). + - fixed bugs in media exporter for non-MPEG4 streams (AMR & co). + - added '-dts' option to MP4Box - dumps samp num, DTS and CTS for all tracks and performs sanity check of CTS offsets. + - added '-split time_sec' option to MP4Box - splits a simple AV IsoMedia file (no systems, only ONE VIDEO stream supported) into several movies of time_sec duration. + - added '-cat' option to MP4Box - concatenates several input file (IsoMedia or not) to a single IsoMedia file. Same options as -add. + ** Streams with different sample descriptions are imported as distinct tracks ** + - fixed bugs in OD and IPMPX parsers (ipmpDescrPtr and IPMP_ToolID) + +30/03/05: GPAC 0.2.4 release + - Added TeXML import (QT XML format for 3GPP text) + - Added SRT extraction for text tracks. + - Added SUB subtitles support (SUB->3GPP text, SUB->BIFS) + - New lifting for MP4Box - nicer progress notifications and help screens. + - changed MP4Box to OVERRIDE FILES BY DEFAULT if '-out' is not specified. + - changed MP4Box to use 0.5sec interleaving storage by default on all operations. + - added file associations for Osmo4/Win32 (not for wx version) + - added volume control and playlist restoring (Osmo4_w32 and Osmo4_wx) as well as fullscreen restoring when changing file through playlist + - added '-unhint' option in MP4Box to remove all hinting from file. + - many rewrite and fixes in WinCE version (Osmo4 and gapi), much more stable and usable player. + - changed SBR import in MP4Box: -sbr for backward compatible HE-AAC (implicit) signaling, -sbrx for non-backward compatible (explicit) signaling. + - added bandwidth signaling in SDP (b=AS:X) for some players compatibility + - added H263 and MPEG4 Visual(CMP) importers in MP4Box + - added extra SDP lines support in MP4Box - PLEASE refer to rfc2327 before complaining :) + - added hinters for QCELP (RFC 2658) and EVRC/SMV (RFC 3558). Not tested (no decoder available) - QCELP hinter works with QT6.5. + - added QCP importer/export in MP4Box and raw EVRC and SMV importers (not tested) + - added support for 3GPP2 extensions in IsoMedia (EVRC, QCELP and SMV config) + - added basic media cache for stream recording (rtp, internet radios). Only MP4 cache available, but other formats possible (plugin) + - added raw samples export and avi track to raw export in MP4Box + - More H264: import/export/rtp hinter in MP4Box, rtp reassembler + - Basic ISMACryp support in client (RTP and file) + - ISMACryp hinter in MP4Box + - ISMACryp support in MP4Box - cf "MP4Box -h crypt" for more details. Selective encryption (sample-based) is supported but not key switching (only one key at this time). + - added smaller version of libmcrypt to M4Systems library for ISMA AES-128 CTR (but kept other algos for future IPMPX usage) + - added simple converter from cubic QTVR to MP4 + - added 3GGP AMR NB and WB (float code) plugin (Fixed Point AMRWB is just so slow ....) + - moved 3GGP AMR NB decoder to 600 release (old lib should still be compatible) + - moved to latest official ffmpeg tarball for AVC B-frames decoding support (older ffmpeg versions should still work despite some API changes) + - added IPMPX base code (read/write and BT/XMT dump/parse) + - added chunk encoding in MP4Box (uses 2 input files, one with base scene, one with BIFS updates only) + - changed OGG muxing in MP4 - one single OTI (0xDD) used for all OGG streams - DSI format same as before. + - Fixed bug in CTTS computing in MPEG4 Video import caused by consecutive I frames. + - fixed MPA hinter RTP agregation mode (was always on). + - misc updates in importers, exporters and ISMACryp APIs + - cleaning of ISMA and 3GP related stuff in m4systems, forced 3GP file to be branded '3GP5' for QT compatibility... + - rewrote AMR hinter for RTP agregation, added maxptime hint param for speech rtp payloads (AMR/QCELP/EVRC/SMV). + - Fixed MediaControl/Inline URL changing + - fixed video RTP timescale in hinters for QT compatibility + - fixed language-based alternate stream selection in ODs + - cleanup of m4_config.h (removing all unneeded includes, misc cleanup for FreeBSD port) + - brought XMT-A in line with spec regarding MFString/MFURL/MFScript (parsers and dumpers) + - added support for "od://" in XMT-A urls according to XMT spec + - fixed raw aac export bug + - fixed DIV5 import issues with PLs + +05/01/05: GPAC 0.2.3 release + - new regression tests (X3D and some other features) + - MPEG-4 playback from BT/XMT now supports proper startTime/stopTime behaviour + - found a port of XVID for WinCE/ARM, removed OpenDivX from distribution (seemed no longer maintained). This XviD port is BTW much faster & more reliable than old OpenDivx + - split codec_pack in xvid_dec, img_in and mp3_in plugins + - fixed ffmpeg H264 support + - scene time for VRML/X3D now complies with spec (VRML uses absolute UTC timing since 1970) + - fixed 3D spot/point lighting bug + - added support for raw AMR file format (AMR and AMR-WB, multichannel AMR not supported) in MP4Box (import/extract) and reader plugin. + - added MP4Box '-tmp directory': forces temp file creation to given directory rather than OS-specific temp file storage. + - integrated the very nice mpeg ps parser from MPEG4IP - MP4Box now supports MPEG PS import to MP4 (ATM only one audio, one video, and only MP3 audio) + - added basic MPEG 1/2 Video RTP hinter and reassembler, checked MPEG files hinted to MP4 compatibility with QT player. + - fixed color transform and texturing issues. + - various fixes due to "dynamic scenes" in RTP stack and ESM module + - fixed copy/paste in Osmo4 address bar, mp4 on http issues, MP4Box -add pbs with IsoMedia + - Freezing TTXT format version 1.0 - documentation avail on gpac.sf.net + - Updated MP4Box documentation on gpac.sf.net to 0.2.3 version. + - Changed NetClientPluggin API (got rid of status query, status handled internally in ESM and in plugin if needed) + - Updated evc3 projects, made M4Systems READ/WRITE on CE to enable timedtext parsing (and future streaming cache, who knows ...). + - Added 3GPP text hinting in MP4Box and 3GPP text reassembler in rtp plugin. + - Bug fixes and testing of 3GP timed text with some 3GP files + - GF_InlineScene now supports MediaControl with mediaStartTime and mediaStopTime + - AAC SBR import now uses backward compatible decoder config. + - 3GPP/MPEG4 timed text decoder - supports everything except soft wrap & dynamic highlighting (karaoke) - vertical text not fully tested + - new "ttxt" format (for "timed text"): XML representation of 3GPP/MPEG4 timed text streams - importer (from ttxt and from srt) and dumper (to ttxt only) support. + - MP4Box "-ttxt" option: converts an SRT file to a TTXT one. + - Input plugin for ttxt and srt files. + - Support for "dynamic scenes", eg gpac will now generate on the fly a scene description when none is found, and allows stream selection in GUI. + - Modified Osmo4 & wxOsmo4 GUI: stream selection & subtitle adding + - Changed MP4Box "-import" to "-convert" ("-import" is kept for backward compatibility). + - Added MP4Box -nosys (removes all MPEG-4 systems streams and writes an empty IOD) + - Added MP4Box "-add": adds any supported format to an mp4 file (same input conventions as -convert). Several input can be specified (ex: -add audio1.aac -add sub1.srt video.mp4 -out full_movie.mp4) + - fixed a nasty bug in RTSP stack screwing up all mediaControl & rtsp session. + - 3D NonLinearDeformer (AFX) support (taper, twister and bender) + - Completed X3D geometry set: LineSet, (Indexed)TriangleSet, (Indexed)TriangleStripSet, (Indexed)TriangleFanSet + - Full multichannel audio mixing and resampling (and better audio speed support). Multichannel->stereo conversion (not configurable atm). + - Yet Another Announcement of a stable ffmpeg demuxer - stable with avi & mpeg, still sync issues with some QT files (same issues with ffplay). + - added SBR mode for aac importing ('-sbr' switch) in MP4Box. + - fixed: MP4Box hinters (empty tracks), SDL -> BIFS coord mapping in fullscreen, rounding segmentDescriptor.startTime pbs in seeking with mp4menu + - Added Playlist and brower-like navigation to Osmo4 and wxOsmo4 + - AAC/ADTS file & streaming input (radios) - FAAD decoder moved to aac_in plugin + - ADTS import/extraction in MP4Box + - fixed OD XMT-A for ESD.OCR_ES_ID and ESD.dependsOn_ES_ID (now use IDREFs and not binary IDs) + - integrated ogg lib in gpac (), and added ogg/vorbis and ogg/theora importers to mp4 - THIS IS NOT STANDARD AT ALL. + The current syntax is to put needed headers in the MPEG-4 DecoderSpecificInfo, with the following syntax: + u16 sizeof_header; + char *header_data; + for each header (quite similar to what is found in qtcomponents). Vorbis ObjectTypeIndication is 0xDE, theora ObjectTypeIndication is 0xDF. + Need some more testing before filing a request to mp4ra.org. + Streaming possible as MPEG-4 streams, Vorbis RTP packetizer still to be done. + +09/11/04: GPAC 0.2.2 release + - Xiph OGG demuxer: supports file, http download (not tested) and icecast servers. + - Xiph Vorbis decoder + - Xiph Theora support (should work with fluendo but I can't get any data from the server...) + - Better FFMPEG support (moved to latest ffmpeg cvs tarball). + - all file associations in client are made through mime types, and changed handling of service (mime type query if possible before loading plugin) + - network stats & changed all UIs for that. + - decoder stats & changed all UIs for that. + - nicer Osmo4/wxGTK + - shoutcast support in mp3 reader + - Install doc cleanup + - MP4Box "-single" option now work for 3GP files + - MP4Box "-rem TrackID" option to remove a track + - made 3GP hinter produce QT-compatible streams (as usual QT only accepts specific RTP timescales) + - moved M4Systems to a dynamic lib (static is still first built & used for MP4Box) + - moved all scene decoders (bifs, OD and context loader) to real plugins + - moved BT & XMT parsers from stdio to ZLIB io, in order to support GZIPed VRML & X3D (and consequently, BT and XMT-A ;). GPAC CAN NO LONGER COMPILE WITHOUT ZLIB + - massive cleanups in scenegraph & MPEG-4 node naming convention + - !!!scene graph no longer customizable without code hacking!!! + - X3D scene graph generator (decided NOT TO SUPPORT VRML 97 extensions, since they are in X3D and with a different format...) + - updated vrml tools for X3D support (Double precision coords & RGBA colors) + - culling of AABB tree against frustum at draw stage in 3D renderer - greatly speeds up large meshes & terrains rendering + - support for weird cyclic graphs in scenegraph (mainly to support encoding of conditionals). Works with nodes as well, configurable through scenegraph but this can + likely crash a renderer other than GPACs (tested with blaxxun & old GPAC versions, crash works each time:) + - lighting and transformations now properly set in 3D renderer + - improved gravity (ground detection) and added jump in walk mode (right click or 'j') + - support for streams without systems timing knowledge (non MPEG4), eg streams where timing is computed after decoding (and not given by transport layer) for simpler ogg support. + - support for multiple URL in VRML nodes (including remote script) + - '#Viewpoint' and 'URL#Viewpoint' support in Anchor and Inline - #segment_name is not supported and should not be used (not standard IMHO) + - ColorRGBA support for X3D + - texture generator (only "SPHERE-LCOAL" and "COORD" supported for now) + - XML scene dumper now supports X3D (scene dumping API has changed) + - X3D support in BT and XMT-A loader + - updated 3D renderer & ESM for X3D support + - added X3D geometry2D nodes in 3D renderer + - Anchor.activate now works with no children + - plethora of bug fixes + + +15/10/04: GPAC 0.2.1 release + - massive fixes in javascript (assignment was only 50% working), new faster, less memory-hungry implementation (and Othello reg test now passes!!) + - CreateVrmlFromScript support for VRML content. + - collision detection + - gravity (not really working) + - Layer3D fully supported (including navigation!) + - InputSensor in non-encoded scenes (bt/xmt) + - aabb tree in 3D meshes for faster picking/collision - needs more cfg options though + - user input in composite texture 2D/3D, and completed TouchSensor (hitNormal & texCoords event out) in 3D renderer + - added full blending support in 3D renderer (depth sorting) + - fixed handling of clipers (layout/form) and layer2D. + - added text change checking in spidermonkey to avoid rebuilding text + - support for usual coords in 2D renderer (window top-left in 0, 0 and decreasing y) for SVG integration + - 3D normal renormalization for GL when scaling (eg now there's a proper lighting) + - 4/3 and 16/9 aspect ratio modes now work as expected + - interactions with fullscreen SDL now happen where they should + - LinearGradient and RadialGradient in 3D renderer + - hide all scene context importing through a single ContextLoader object to get first frame and progress info for swf loading in player + - added Orbit navigation mode (orbit around the user look point) & updated interfaces + - massive cleanup of scene handling & decoders to enable run-time modules for scene decoding. APIs have changed, 2 new ones for scene decoders and media decoders + - finished BT/XMT/WRL scene handler and added support for SWF. + - added toolbar for Osmo4_w32 (_wx one to come) + - added PlanarExtrusion hardcoded proto (2D shape extruded by 2D shape) + - added bt/wrl support in MP4Client, update scene graph accordingly to use a single graph & lots of related fixes in ESM + - added texture text support in 3D renderer (graphics plugin being now loaded by main renderer) + - upgraded avilib to latest version from ogmtools (should support OpenDML 2.0) + - updated configure, Makefiles, & EVC3 project files + - textured text support (eg render to texture then blit) in 2D renderer + - ElevationGrid, Extrusion, VisibilitySensor, LOD support + - Sound support (stereo spatializer only) and reworked generic audio renderer for Sound/Sound2D support + - MPEG-4 V5 animators (not complete) + - reworked hardcoded proto mechanism to comply with VRML recommendations - some doc to come soon + - hardcoded proto PathExtrusion for any 2D shape extrusion except Bitmap and PointSet2D - eg EXTRUDED TEXT SUPPORT :) + - fixed Win32 large file support in GPAC, needs testing of AVI importer... + - cleaned up multichannel support, fixed faad channel reordering + - added background support: sky & ground dome, cube image (6 sides) + - added navigation support (WALK/FLY/EXAMINE/ + extra modes a la blaxxun) and user selection in Osmo4/wxOsmo4 and MP4Client + - added animation between viewpoints + - changed handling of empty boundable stacks according to VRML: no more default backColor, and real 3D scenes (top=Group or Layer3D) no longer may use orthographic projections + - normal smoothing for IFS. + - full lighting support (spot, point and directional) + - fog and billboard support. + - basic AVC support in MP4 (only AVCSampleEntry and child atoms) + - VRML/MPEG-4 interaction sensor support (added ProximitySensor, SphereSensor, PlaneSensor and CylinderSensors). still some work to do on TouchSensor hitNormal & hitTex + - SWF parser updates: PlaceObject2 and defineShape2.NewStyle bugs, support for soundStream + - added user interaction in 3D renderer (ray casting) in both ortho and projection modes + - frustum is now only recomputed when change in size or viewpoint + - viewport/viewpoint selection to osmo4/wxOsmo4 GUIs + - BT parser supports basic VRML (uncompressed .WRL should now be imported fine) + - plethora of bug fixes + +02/09/04: GPAC 0.2.0 release + - updated cfg file doc man pages & makefiles + - massive re-arch of renderer(s) to be able to load at run-time either 2D or 3D renderer, instead of static linking + - new 2D and 3D renderers + - re-organized development headers + - added basic file<->plugin association by file extension (cf doc) + - Osmo4/wxWidgets version in Applications/Osmo4_wx + - put zoom & pan back in place in 2D render plugin + - fixed V4Studio (upgrade to wxWidgets 2.5.2) + - MP42AVI supports 3D scenes duming + - updated templates for v5 & v6. WARNING: it seems that some nodes will be removed from v5 (AFX COR) which will invalidate v6 bitstreams + - still more fixes related to scenegraph arch changes + - reworked importers & exporters + - updated new regression test suite (no 3D yet) + - bug fixes in MediaControl, MediaSensor & inline scene control + - more fixes related to scenegraph arch changes + - cleanup of SWF importer: + * shape importing is OK, gradient so-so (wrong matrix mapping), no bitmap fill + * font & text OK. + * sprites should work + * sound work - sound stream not done yet + there will likely not be any new SWF feature supported, ActionScript & buttons are out of scope for GPAC. + - added swf support from MP4Box (cf -swf switch) + - fixed XMT-A syntax of script and proto SF/MFNode field, and BIFS/XMT UTF-16 support + - fixed avg/max rate compute on large files for AVI and MP3 importers + - Background2D texturing uses hw blitter when possible (2D renderer only) + - better inline scene & segment descriptors handling + - encoding of IOD extra descriptors now supported + - configure script fixes + - changed all 3D handling, encapsulating all GL calls in a single file + - moved all primitives in 3D renderer to use a single mesh object (rendering done through vertex arrays) + - added IFS, ILS, Sphere + - optimized AVI importer, fixed vbr mp3 in avi import + - changed scenegraph: + * all nodes now keep track of their parents in order to signal sub-tree changes for frustum culling + * no more "SimulationTime" used in scenegraph, using node modif flags instead + * updated 2D and 3D renderer accordingly + - added support for rectangular textures in GL (most graphic cards support this, at least on win32) + - added frustum culling + - added SFTime->SFString formating in valuator (current MPEG-4 COR) + - plethora of bug fixes + +11/05/04: JLF: dev version 0.1.9 + - changed source code architecture: rendering code is now in a dedicated static link outside libm4systems + - intergated draft 3D renderer: + - Most 2D features have been ported to the new renderer (missing: viewport, colorTransform and gradients) + - no user interaction, no viewpoint, no background, no lighting, NO ETC !!!! + - Box, cylinder, cone working + - texture mapping working (still images and video) + - changed video plugin API accordingly + - changed graphics API: all path handling (building & flatening , outlining & dashing) moved to authoring subproject + - changed font API: no more graphics driver used to get font outline + - cf install documentation to recompile. + - updated all node tables to COMPLETE BIFS (eg all nodes from v1 to v6) + - updated v6 template & code to final amendment version + - fixed inline scene start/stop when modifying inline URL. + - updated TODO :) + - uploaded ultra basic SWF convertor (so that it doesn't get lost on my hard drive:) + - plethora of bug fixes + +28/04/04: GPAC Release 0.1.4 + - MP4Box avi import fixes (key frames, VOL removal, n-VOP handling) + - Fixed MP4 and NHNT importers (visual tracks sizes) + - MP4Box avi extractor for visual tracks + - XMT-A parser fixes (unicode, DEF routes, proto namespaces) + - better ExternProto resolving + - added VRML addressing (eg url "protolib#protoName" and "protolib#protoID") + - added pause/resume in Layout scrolling + - fixed rendering of layout nodes (layout, Form and Layer2D) in layout nodes + - fixed port reuse bug: 2 instances of the client may now use RTP streaming (UDP or TCP) at the same time + - fixed video Profile and Levels handling (was old 2000 spec version) + - added -merge option in MP4Box (merges 2 files into a single AV file) + - Fixes in SDL surfaces handling + - better "end of presentation" support + - plethora of bug fixes + +18/04/04: JLF: GPAC Release 0.1.3 rc2 + - MP4Box default hinting is now QT compatible - b-frame hinting support + - DecodingBuffer and CompositionMemory occupancey in ODInfo + - layout text splitting (word boundaries only) + - linux install and man pages + - OCR stream support in (authoring/playing) - only tested with MP4. MediaControl supported on OCR + - MP4Box B-frame import now works with data referencing + - fixed many seeking and buffering issues + - multi-framed audio units (needed for most formats understood by ffmpeg demux) + - multiplexed input streams now properly setup + - networking under linux (http and rtp) + - fixed udp streaming on win32/winCE, rtp reordering (was never on), default udp buffer size. + - changed config file for reordering + - changed audio driver interface (retrieve the HW config on setup for SDL) + some audio resync addons + - support for console events detection in MP4Client linux (a la win32 kbhit()) + - anchor (mp4 navigation only) support in MP4Client + - uploaded linux version of extra libs + - added non-system SDL support in GCC configure script (cf --sdl-cfg) + - default font handling in freetype plugin: some text will be diplayed if at least one font is present + - better MPEG-4 video import (B-frame and packed bitstream) + - updated MP4 with full trackHeader (was old v1) and fixed MP4Box compatibility issues with 3ivx splitter + - moved all windowing architecture to the video output plugins (keyboard and mouse events, WM messages) in order to support SDL, moved old input functions to new event model + - modified jconfig.h to support both win32 and MinGW. + - updated V4Studio to work with new event/windowing architecture (work with SDL and DX) + - UDP autoconfig option (if no UDP traffic is recieved, restart with TCP) + - moved to FAAD2.1 (CVS), fixed faad2 compil on MinGW & winCE + - cleaned up install docs + - added support for SDL with software YUV->RGB and software stretching + - fixed ffmpeg audio support + - added ffmpeg JPEG support + - moved to FreeType 2.1.7 + - moved to libmad 0.15.1b + - MinGW support in all extra libs + - MinGW compilation supported - including DirectX under mingw + - added support for xvid 1.0.0 + - plethora of bug fixes + +28/01/04: GPAC Release 0.1.2 + - codec selection in Osmo4 GUI + - PocketPC installer + - OpenDivx plugin + - clean-up extra lib package, install notes and added missing libs + - FFMPEG demuxer done (synchro not good and seeking pbs). GPAC now supports all FFMPEG-supported formats. + - new NSIS script for complete install + - fixed hang on PocketPC WavOut and misc cleanups for PocketPC compilation + - H263 in 3GP files (use FFMPEG dec) + - H263 streaming (RFC 2429) + - B-frame parsing and CTS reconstruction in AVI importer (needs debug). + - muxInfo.duration parameter is now in milliseconds (was in seconds) + - '-node' options to MP4Box to get a given node syntax (fields default value and QP info) + - relative time stamps in BT ('AT D1000 ' means 'at last AU TS + 1000') + - FFMPEG decoder plugin now working with latest CVS snapshot + - MediaControl switching (several MC on single object) + - separate file downloader API and streaming client API / cleanup of plugins and ESM module + - base support for non-MPEG4 URLs in the scene (eg, url "http://whatever/resource") + - loader (local/network) for JPEG and PNG files + - loader (local/network) for MP3 files. Would be nice to add SHOUTCAST/ICECAST too... + - support for ESD URLs and non-inline OD URLs (supports any service, local file, download and streaming) + - MP4Box no longer needs SpiderMonkey + - added MatteTexture support (needs testing and debug) + - cleanup of exported headers (install in ) + - move all config info to a single include file and updated some compil macro to avoid touching the file + - persistant associations font name / file name for freetype in GPAC.cfg + - support for conditional in proto creating node interfacing with the proto + - complete XMT-A parser (script, proto, externProto and extendedUpdates) + - edit list support in MP4 reader plugin + - BT->XMT-A and XMT-A->BT in MP4Box + - support for MP4 track start offset in BT/MP4Box (edit Lists) + - BIFS random access point generation in MP4Box (sync shadow or regular RAP) for cartoons + - AMR NB support (payload parsing and 3GP codec plugin) + - plethora of bug fixes + +20/11/03: GPAC Release 0.1.1 + - 3GP rtsp streaming support + - GPAC uses latest stable extra libs: faad2 2.0rc3, FreeType 2.1.5 and mad 0.15.0b, and dev version (20031117) of xvid + - support for MediaSegment ranges ("#seg+" and "#seg1-seg2") in MediaControl/MediaSensor + - flow control for RTP over RTSP and session restart when RTSP TEARDOWN not acknowledged + - 3GPP hinting (AMR NB and H263) contribution by Andrew Voznytsa + - playback support for basic 3GPP files (that is only MPEG-4 visual and AAC audio) + - support for MPA payload format - RFC 2250 (hinting and playback) + - support for mode detection (CELP and AAC) in hinting since QT6 understands only these modes + - support for several mediaSensors per OD + - AudioBuffer + - removed DirectDraw display resolution changes when switching to fullscreen + - BIFS Extended Updates from AFX/MU amendment (integrated in GF_SceneGraph, dumping, memory decoding and encoding) + - BT parser completed - complete BIFS syntax is now supported except PMF + - SRT importer through BT (converts SRT file to a BIFS animationStream) + - better audio playback/sync + - ffmpeg plugin, decoder seems OK (MPEG1 and MPEG4 visual tested), demuxer not working yet. + - added AVI/mp3/MP4/NHNT import to mp4box + - BIFS encoder initial release (missing: PMF, BIFS extended Updates), bt parser almost done, bt->mp4 working + - exporters in MP4Box (cmp, aac, mp3, jpg, png and nhnt) + - mp4 XML reports for hint tracks and atoms in MP4Box + - merged old soft rasterizer with charcoal + freetype (using ftgrays standalone raster) - better quality, faster ... + - added BIFS stat tools in MP4Box + - lots of updates in dirty rect algo. + - changed GraphicsDriver2D API + - scene graph dumper in Osmo4 win32 + - New app MP42AVI for BIFS to video (AVI, BMP, RAW) conversion, single-frame dump support + - MP4 dumping to XMT-A and bt (BIFS, OD and OCI) - cf MP4Box + - PredictiveMFField support (only IPPPPPPP...) + - segment descriptors in MediaControl + - ported wav audio for WinCE - TEST AND FIXING NEEDEED , DOESN'T WORK ON ALL IPAQs + - support for hardcoded proto testing + - WinCE port + GAPI video renderer (for iPaq only) + - externProto support (only tested with local proto libs) + - InputSensor (keySensor, Mouse and StringSensor) + - plethora of bug fixes + +version 0.1.0: + initial release diff --git a/Clean.bat b/Clean.bat new file mode 100644 index 0000000..e619504 --- /dev/null +++ b/Clean.bat @@ -0,0 +1,23 @@ +cd src +DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph +cd .. + +cd modules +DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph +cd .. + +cd build +DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph +cd .. + +cd applications +DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph +cd .. + +cd bin +DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph +cd .. + + + + diff --git a/INSTALLME b/INSTALLME new file mode 100644 index 0000000..d6d61b0 --- /dev/null +++ b/INSTALLME @@ -0,0 +1,69 @@ +Installation instructions for latest GPAC GIT version - March 2015: + +For Windows, Linux and Mac OS X versions, follow the instructions on http://gpac.sourceforge.net/home_download.php + +For Android, follow the instructions in gpac/build/android/README + +(WindowsMobile platform i sno longer maintained) +For WindowsMobile platform, get the latest package of gpac extra libs available here: + +https://sourceforge.net/p/gpac/code/HEAD/tree/trunk/gpac_extra_libs/ + +and follow the instructions in gpac/doc/INSTALL.wCE + + + +Other Installation instructions for GPAC + + +* Foreword + + GPAC may be compiled without any third party libraries, but in this case its functionalities are very +limited (no still image, no audio, no video, no text, no scripting). It is therefore recommended to download the +extra lib package available at http://sourceforge.net/projects/gpac. Compilation instructions for these libraries +are provided per library in the package. + + The current extra_lib package to use with gpac 0.5.0 and above is gpac_extra_libs available here: +https://sourceforge.net/p/gpac/code/HEAD/tree/trunk/gpac_extra_libs/ + + In case you have some of these libs already installed on your system, the detailed list of dependencies is + * freetype2 from version 2.1.4 on. + * SpiderMonkey v1.7 (libjs from mozilla). + * libjpg version 6b + * Libpng version 1.2.33 (older versions should work) + * MAD version 0.15.1b (older versions should work) + * xvid version 1.0 (0.9.0 / .1 / .2 should also work) + * ffmpeg (latest stable API version checked was 08 February 2007 snapshot, you may need to change a few things with current versions) + * libogg 1.1, libvorbis 1.1 and libtheora 1.0 from Xiph.org (newer versions work) + * faad2, version 2.0 or above (2.6.1 working) + * liba52, version 0.7.4 + * OpenJPEG, version 1.3 + * OpenSVCDecoder, version 1.3 + +* Installing GPAC + +/!\ GPAC won't compile if the 'git' command is not in your path /!\ + +!! WARNING !! +The following instructions may not be completely up to data +You should use online instructions which may be more up-to-date: +http://gpac.io/2011/04/18/command-line-gpac-compiling-on-windows-x86-using-free-microsoft-visual-c/ + +Detailed instruction for Win32 MSVC Compilation are available in gpac/doc/INSTALL.w32 + +Detailed instruction for WinCE eVC Compilation are available in gpac/doc/INSTALL.wCE + +Detailed instruction for GCC Compilation are available in gpac/doc/INSTALL.gcc + +Detailed instruction for GCC cross-compilation for familiar+GPE systems are available in gpac/doc/INSTALL.gpe + +Detailed instruction for GCCE/Symbian cross-compilation for Symbian v9.1 systems are available in gpac/doc/INSTALL.symbian + +Detailed instruction for iOS Compilation are available in gpac/build/xcode/README_IOS.txt + +* Configuring GPAC + +GPAC's client configuration is documented in gpac/doc/configuration.html +MP4Box documentation is available online at http://gpac.sourceforge.net + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..62b7850 --- /dev/null +++ b/Makefile @@ -0,0 +1,287 @@ +# +# Main gpac Makefile +# +include config.mak + +vpath %.c $(SRC_PATH) + +all: version + $(MAKE) -C src all + $(MAKE) -C applications all +ifneq ($(MP4BOX_STATIC),yes) + $(MAKE) -C modules all +endif + +GITREV_PATH:=$(SRC_PATH)/include/gpac/revision.h +TAG:=$(shell git --git-dir=$(SRC_PATH)/.git describe --tags --abbrev=0 2> /dev/null) +VERSION:=$(shell echo `git --git-dir=$(SRC_PATH)/.git describe --tags --long || echo "UNKNOWN"` | sed "s/^$(TAG)-//") +BRANCH:=$(shell git --git-dir=$(SRC_PATH)/.git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "UNKNOWN") + +version: + @if [ -d $(SRC_PATH)/".git" ]; then \ + echo "#define GPAC_GIT_REVISION \"$(VERSION)-$(BRANCH)\"" > $(GITREV_PATH).new; \ + if ! diff -q $(GITREV_PATH) $(GITREV_PATH).new >/dev/null ; then \ + mv $(GITREV_PATH).new $(GITREV_PATH); \ + fi; \ + else \ + echo "No GIT Version found" ; \ + fi + +lib: version + $(MAKE) -C src all + +apps: + $(MAKE) -C applications all + +sggen: + $(MAKE) -C applications sggen + +mods: + $(MAKE) -C modules all + +instmoz: + $(MAKE) -C applications/osmozilla install + +depend: + $(MAKE) -C src dep + $(MAKE) -C applications dep + $(MAKE) -C modules dep + +clean: + $(MAKE) -C src clean + $(MAKE) -C applications clean + $(MAKE) -C modules clean + +distclean: + $(MAKE) -C src distclean + $(MAKE) -C applications distclean + $(MAKE) -C modules distclean + rm -f config.mak config.h + +lcov_clean: + lcov --directory . --zerocounters + +lcov: + lcov --capture --directory . --output-file all.info + rm -rf coverage/ + lcov --remove all.info /usr/pkg/include/gtest/* /usr/pkg/include/gtest/internal/gtest-* \ + /usr/pkg/gcc44/include/c++/4.4.1/backward/binders.h /usr/pkg/gcc44/include/c++/4.4.1/bits/* \ + /usr/pkg/gcc44/include/c++/4.4.1/ext/*.h \ + /usr/pkg/gcc44/include/c++/4.4.1/x86_64-unknown-netbsd4.99.62/bits/gthr-default.h \ + /usr/include/machine/byte_swap.h /usr/pkg/gcc44/include/c++/4.4.1/* \ + /opt/local/include/mozjs185/*.h /usr/include/libkern/i386/*.h /usr/include/sys/_types/*.h /usr/include/*.h \ + --output cover.info + genhtml -o coverage cover.info + +dep: depend + +# tar release (use 'make -k tar' on a checkouted tree) +FILE=gpac-$(shell grep "\#define GPAC_VERSION " include/gpac/version.h | \ + cut -d "\"" -f 2 ) + +tar: + ( tar zcvf ~/$(FILE).tar.gz ../gpac --exclude CVS --exclude bin --exclude lib --exclude Obj --exclude temp --exclude amr_nb --exclude amr_nb_ft --exclude amr_wb_ft --exclude *.mak --exclude *.o --exclude *.~*) + +install: + $(INSTALL) -d "$(DESTDIR)$(prefix)" + $(INSTALL) -d "$(DESTDIR)$(prefix)/$(libdir)" + $(INSTALL) -d "$(DESTDIR)$(prefix)/bin" +ifeq ($(DISABLE_ISOFF), no) +ifeq ($(CONFIG_LINUX), yes) +ifneq ($(CONFIG_FFMPEG), no) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/DashCast$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" +endif +endif +endif +ifeq ($(DISABLE_ISOFF), no) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Box$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" +ifneq ($(MP4BOX_STATIC), yes) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP42TS$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" +endif +endif +ifneq ($(MP4BOX_STATIC), yes) +ifeq ($(DISABLE_PLAYER), no) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Client$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" +endif +endif + if [ -d $(DESTDIR)$(prefix)/$(libdir)/pkgconfig ] ; then \ + $(INSTALL) $(INSTFLAGS) -m 644 gpac.pc "$(DESTDIR)$(prefix)/$(libdir)/pkgconfig" ; \ + fi + $(INSTALL) -d "$(DESTDIR)$(moddir)" +ifneq ($(MP4BOX_STATIC),yes) + $(INSTALL) bin/gcc/*$(DYN_LIB_SUFFIX) "$(DESTDIR)$(moddir)" + rm -f $(DESTDIR)$(moddir)/libgpac$(DYN_LIB_SUFFIX) + rm -f $(DESTDIR)$(moddir)/nposmozilla$(DYN_LIB_SUFFIX) + $(MAKE) installdylib +endif + $(INSTALL) -d "$(DESTDIR)$(mandir)" + $(INSTALL) -d "$(DESTDIR)$(mandir)/man1"; + if [ -d doc ] ; then \ + $(INSTALL) $(INSTFLAGS) -m 644 doc/man/mp4box.1 $(DESTDIR)$(mandir)/man1/ ; \ + $(INSTALL) $(INSTFLAGS) -m 644 doc/man/mp4client.1 $(DESTDIR)$(mandir)/man1/ ; \ + $(INSTALL) $(INSTFLAGS) -m 644 doc/man/gpac.1 $(DESTDIR)$(mandir)/man1/ ; \ + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac" ; \ + $(INSTALL) $(INSTFLAGS) -m 644 doc/gpac.mp4 $(DESTDIR)$(prefix)/share/gpac/ ; \ + fi + if [ -d gui ] ; then \ + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui" ; \ + $(INSTALL) $(INSTFLAGS) -m 644 gui/gui.bt "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ + $(INSTALL) $(INSTFLAGS) -m 644 gui/gui.js "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ + $(INSTALL) $(INSTFLAGS) -m 644 gui/gwlib.js "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ + $(INSTALL) $(INSTFLAGS) -m 644 gui/mpegu-core.js "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui/icons" ; \ + $(INSTALL) $(INSTFLAGS) -m 644 gui/icons/*.svg "$(DESTDIR)$(prefix)/share/gpac/gui/icons/" ; \ + cp -R gui/extensions "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ + rm -rf "$(DESTDIR)$(prefix)/share/gpac/gui/extensions/*.git" ; \ + fi + +lninstall: + $(INSTALL) -d "$(DESTDIR)$(prefix)" + $(INSTALL) -d "$(DESTDIR)$(prefix)/$(libdir)" + $(INSTALL) -d "$(DESTDIR)$(prefix)/bin" +ifeq ($(DISABLE_ISOFF), no) +ifneq ($(CONFIG_FFMPEG), no) + ln -sf $(BUILD_PATH)/bin/gcc/DashCast$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/DashCast$(EXE_SUFFIX) +endif +endif +ifeq ($(DISABLE_ISOFF), no) + ln -sf $(BUILD_PATH)/bin/gcc/MP4Box$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP4Box$(EXE_SUFFIX) + ln -sf $(BUILD_PATH)/bin/gcc/MP42TS$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP42TS$(EXE_SUFFIX) +endif +ifneq ($(MP4BOX_STATIC),yes) +ifeq ($(DISABLE_PLAYER), no) + ln -sf $(BUILD_PATH)/bin/gcc/MP4Client$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP4Client$(EXE_SUFFIX) +endif +endif +ifeq ($(CONFIG_DARWIN),yes) + ln -s $(BUILD_PATH)/bin/gcc/libgpac$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_MAJOR) + ln -sf $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_MAJOR) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX) +else + ln -s $(BUILD_PATH)/bin/gcc/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) + ln -sf $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so.$(VERSION_MAJOR) + ln -sf $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so +ifeq ($(DESTDIR)$(prefix),$(prefix)) + ldconfig || true +endif +endif + +uninstall: + $(MAKE) -C applications uninstall + rm -rf $(DESTDIR)$(moddir) + rm -rf $(DESTDIR)$(prefix)/$(libdir)/libgpac* +ifeq ($(CONFIG_WIN32),yes) + rm -rf "$(DESTDIR)$(prefix)/bin/libgpac*" +endif + rm -rf $(DESTDIR)$(prefix)/$(libdir)/pkgconfig/gpac.pc + rm -rf $(DESTDIR)$(prefix)/bin/MP4Box + rm -rf $(DESTDIR)$(prefix)/bin/MP4Client + rm -rf $(DESTDIR)$(prefix)/bin/MP42TS + rm -rf $(DESTDIR)$(prefix)/bin/DashCast + rm -rf $(DESTDIR)$(mandir)/man1/mp4box.1 + rm -rf $(DESTDIR)$(mandir)/man1/mp4client.1 + rm -rf $(DESTDIR)$(mandir)/man1/gpac.1 + rm -rf $(DESTDIR)$(prefix)/share/gpac + rm -rf $(DESTDIR)$(prefix)/include/gpac + +installdylib: +ifneq ($(MP4BOX_STATIC),yes) +ifeq ($(CONFIG_WIN32),yes) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.dll.a $(DESTDIR)$(prefix)/$(libdir) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.dll $(DESTDIR)$(prefix)/bin +else +ifeq ($(DEBUGBUILD),no) + $(STRIP) bin/gcc/libgpac$(DYN_LIB_SUFFIX) +endif +ifeq ($(CONFIG_DARWIN),yes) + $(INSTALL) -m 755 bin/gcc/libgpac$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(VERSION)$(DYN_LIB_SUFFIX) + ln -sf libgpac.$(VERSION)$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX) +else + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) + ln -sf libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so.$(VERSION_MAJOR) + ln -sf libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so +ifeq ($(DESTDIR)$(prefix),$(prefix)) + ldconfig || true +endif +endif +endif +endif + +install-lib: + mkdir -p "$(DESTDIR)$(prefix)/include/gpac" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/include/gpac/*.h "$(DESTDIR)$(prefix)/include/gpac" + mkdir -p "$(DESTDIR)$(prefix)/include/gpac/internal" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/include/gpac/internal/*.h "$(DESTDIR)$(prefix)/include/gpac/internal" + mkdir -p "$(DESTDIR)$(prefix)/include/gpac/modules" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/include/gpac/modules/*.h "$(DESTDIR)$(prefix)/include/gpac/modules" + $(INSTALL) $(INSTFLAGS) -m 644 config.h "$(DESTDIR)$(prefix)/include/gpac/configuration.h" +ifeq ($(GPAC_ENST), yes) + mkdir -p "$(DESTDIR)$(prefix)/include/gpac/enst" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/include/gpac/enst/*.h "$(DESTDIR)$(prefix)/include/gpac/enst" +endif + mkdir -p "$(DESTDIR)$(prefix)/$(libdir)" + $(INSTALL) $(INSTFLAGS) -m 644 "./bin/gcc/libgpac_static.a" "$(DESTDIR)$(prefix)/$(libdir)" + $(MAKE) installdylib + +uninstall-lib: + rm -rf "$(prefix)/include/gpac/internal" + rm -rf "$(prefix)/include/gpac/modules" + rm -rf "$(prefix)/include/gpac/enst" + rm -rf "$(prefix)/include/gpac" + +ifeq ($(CONFIG_DARWIN),yes) +dmg: + @if [ ! -z "$(shell git diff master..origin/master)" ]; then \ + echo "Local revision and remote revision are not congruent; you may have local commit."; \ + echo "Please consider pushing your commit before generating an installer"; \ + exit 1; \ + fi + rm "bin/gcc/MP4Client" + $(MAKE) -C applications/mp4client + ./mkdmg.sh $(arch) +endif + +ifeq ($(CONFIG_LINUX),yes) +deb: + @if [ ! -z "$(shell git diff master..origin/master)" ]; then \ + echo "Local revision and remote revision are not congruent; you may have local commit."; \ + echo "Please consider pushing your commit before generating an installer"; \ + exit 1; \ + fi + git checkout -- debian/changelog + fakeroot debian/rules clean + sed -i "s/-DEV/-DEV-rev$(VERSION)-$(BRANCH)/" debian/changelog + fakeroot debian/rules configure + fakeroot debian/rules binary + rm -rf debian/ + git checkout debian +endif + +help: + @echo "Input to GPAC make:" + @echo "depend/dep: builds dependencies (dev only)" + @echo "all (void): builds main library, programs and plugins" + @echo "lib: builds GPAC library only (libgpac.so)" + @echo "apps: builds programs only" + @echo "modules: builds modules only" + @echo "instmoz: build and local install of osmozilla" + @echo "sggen: builds scene graph generators" + @echo + @echo "clean: clean src repository" + @echo "distclean: clean src repository and host config file" + @echo "tar: create GPAC tarball" + @echo + @echo "install: install applications and modules on system" + @echo "uninstall: uninstall applications and modules" +ifeq ($(CONFIG_DARWIN),yes) + @echo "dmg: creates DMG package file for OSX" +endif +ifeq ($(CONFIG_LINUX),yes) + @echo "deb: creates DEB package file for debian based systems" +endif + @echo + @echo "install-lib: install gpac library (dyn and static) and headers , and " + @echo "uninstall-lib: uninstall gpac library (dyn and static) and headers" + @echo + @echo "to build libgpac documentation, go to gpac/doc and type 'doxygen'" + +-include .depend diff --git a/README b/README new file mode 100644 index 0000000..1e52c00 --- /dev/null +++ b/README @@ -0,0 +1,18 @@ +README for GPAC version 0.5.0, May 2012. + +GPAC is a multimedia framework oriented towards rich media and distributed under the LGPL license (see COPYING). +GPAC supports many multimedia formats, from simple audiovisual containers (avi, mov, mpg) to complex +presentation formats (MPEG-4 Systems, SVG Tiny 1.2, VRML/X3D). GPAC supports scripting of presentation for MPEG4/VRML/X3D through +mozilla SpiderMonkey javascript engine. +GPAC currently supports local playback, http progressive download, Adaptive HTTP Streaming (MPEG-DASH, HLS), RTP/RTSP streaming over UDP (unicast or multicast) or TCP and TS demuxing (from file, IP or DVB4Linux). +GPAC also features MP4Box, a multimedia swiss-army knife for the prompt. + +For compilation and installation instruction, check INSTALLME file + +For GPAC configuration instruction, check gpac/doc/configuration.html or gpac/doc/man/gpac.1 (man gpac when installed) + +For more information, visit the GPAC website: + http://gpac.io + + + diff --git a/TODO b/TODO new file mode 100644 index 0000000..3586187 --- /dev/null +++ b/TODO @@ -0,0 +1,7 @@ +todo items as of version 0.5.0: + * more work on DASH support + * improve stereo/multiview renderer and texture+depth support + * more work on DIMS/RME and scene generation support + * rearchitecture of modules + * more SVG support (filter , SVG 2.0) + \ No newline at end of file diff --git a/applications/Makefile b/applications/Makefile new file mode 100644 index 0000000..e60a811 --- /dev/null +++ b/applications/Makefile @@ -0,0 +1,77 @@ +include ../config.mak + +APPDIRS= + +ifeq ($(MP4BOX_STATIC),yes) +APPDIRS+=mp4box +else + +ifeq ($(DISABLE_PLAYER), no) +APPDIRS+=mp4client +endif + +ifeq ($(DISABLE_ISOFF), no) +APPDIRS+=mp4box +ifeq ($(DISABLE_M2TS_MUX), no) +APPDIRS+=mp42ts +endif + +ifneq ($(CONFIG_WIN32), yes) +ifneq ($(CONFIG_FFMPEG), no) +ifneq ($(DISABLE_CORE_TOOLS), yes) +ifneq ($(DISABLE_AV_PARSERS), yes) +APPDIRS+=dashcast +endif +endif +endif +endif + + +endif + +V4STUDIODIR= +INSTDIRS=mp4client +ifeq ($(CONFIG_XUL),no) +else +#INSTDIRS+=osmozilla +#APPDIRS+=osmozilla +endif + +#disable due to version incompatibilities +ifeq ($(USE_WXWIDGETS), yes) +#APPDIRS+=osmo4_wx +#V4STUDIODIR=V4Studio +#INSTDIRS+=osmo4_wx +endif + +#MP4BOX_STATIC +endif + +ALLDIRS=$(APPDIRS) + +all: apps + +apps: + set -e; for i in $(APPDIRS) ; do $(MAKE) -C $$i all; done + +sggen: + $(MAKE) -C generators all + +V4Studio: + set -e; for i in $(V4STUDIODIR) ; do $(MAKE) -C $$i dep; done + +dep: + set -e; for i in $(ALLDIRS) ; do $(MAKE) -C $$i dep; done + +clean: + set -e; for i in $(ALLDIRS) ; do $(MAKE) -C $$i clean; done + +distclean: + set -e; for i in $(ALLDIRS) ; do $(MAKE) -C $$i distclean; done + +install: + set -e; for i in $(INSTDIRS) ; do $(MAKE) -C $$i install; done + +uninstall: + set -e; for i in $(INSTDIRS) ; do $(MAKE) -C $$i uninstall; done + diff --git a/applications/dashcast/Makefile b/applications/dashcast/Makefile new file mode 100644 index 0000000..89eeeda --- /dev/null +++ b/applications/dashcast/Makefile @@ -0,0 +1,77 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/applications/dashcast + +CFLAGS= $(OPTFLAGS) -D_GNU_SOURCE -I"$(SRC_PATH)/include" -I../../ $(ffmpeg_cflags) + +LINKLIBS=$(GPAC_SH_FLAGS) + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +ifeq ($(GPACREADONLY), yes) +CFLAGS+=-DGPAC_READ_ONLY +endif + +ifneq ($(CONFIG_LIBAV),no) +CFLAGS+=-DGPAC_USE_LIBAV +endif + +ifneq ($(CONFIG_LIBAVRESAMPLE),no) +CFLAGS+=-DDC_AUDIO_RESAMPLER +LINKLIBS+=-lavresample +endif + + +#common obj +OBJS= dashcast.o audio_data.o audio_decoder.o audio_encoder.o audio_muxer.o circular_buffer.o cmd_data.o controler.o message_queue.o register.o video_data.o video_decoder.o video_encoder.o video_muxer.o video_scaler.o task.o + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=DashCast$(EXE) +else +EXT= +PROG=DashCast +endif + +LINKLIBS+= $(ffmpeg_lflags) + +ifeq ($(CONFIG_DARWIN), yes) +#fixme - use proper detection of libavdevice dependencies +LINKLIBS+=-lavfilter -lswresample -lbz2 +endif + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +DashCast$(EXE): $(OBJS) + $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(LINKLIBS) + +clean: + rm -f $(OBJS) ../../bin/gcc/$(PROG) + +install: clean + install -m 755 $(INSTFLAGS) ../../bin/gcc/DashCast "$(DESTDIR)$(prefix)/bin" + +uninstall: + rm -rf $(DESTDIR)$(prefix)/bin/DashCast + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/dashcast/audio_data.c b/applications/dashcast/audio_data.c new file mode 100644 index 0000000..5512d0f --- /dev/null +++ b/applications/dashcast/audio_data.c @@ -0,0 +1,97 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "audio_data.h" + + +void dc_audio_data_set_default(AudioDataConf *audio_data_conf) +{ + strcpy(audio_data_conf->filename, ""); + strcpy(audio_data_conf->format, ""); + strcpy(audio_data_conf->codec, ""); + audio_data_conf->bitrate = -1; + audio_data_conf->channels= -1; + audio_data_conf->samplerate = -1; +} + +void dc_audio_data_init(AudioDataConf *audio_data_conf, char *filename, char *format) +{ + if (filename != NULL && strlen(filename) > 0) + strcpy(audio_data_conf->filename, filename); + else + strcpy(audio_data_conf->filename, ""); + + if (format != NULL && strlen(format) > 0) + strcpy(audio_data_conf->format, format); + else + strcpy(audio_data_conf->format, ""); +} + +int dc_audio_input_data_init(AudioInputData *audio_input_data, int channels, int samplerate, int num_consumers, int mode) +{ + int i; + + dc_producer_init(&audio_input_data->producer, AUDIO_CB_SIZE, "audio decoder"); + dc_circular_buffer_create(&audio_input_data->circular_buf, AUDIO_CB_SIZE, mode, num_consumers); + + for (i = 0; i < AUDIO_CB_SIZE; i++) { + AudioDataNode *audio_data_node = gf_malloc(sizeof(AudioDataNode)); + audio_input_data->circular_buf.list[i].data = (void *) audio_data_node; + + audio_data_node->abuf_size = MAX_AUDIO_PACKET_SIZE; + audio_data_node->abuf = gf_malloc(audio_data_node->abuf_size * sizeof(uint8_t)); + } + + audio_input_data->aframe = FF_ALLOC_FRAME(); + if (audio_input_data->aframe == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize AudioInputData")); + return -1; + } + + audio_input_data->channels = channels; + audio_input_data->samplerate = samplerate; + + return 0; +} + +void dc_audio_input_data_destroy(AudioInputData *audio_input_data) +{ + int i; + if (audio_input_data->circular_buf.list) { + for (i = 0; i < AUDIO_CB_SIZE; i++) { + AudioDataNode *audio_data_node = audio_input_data->circular_buf.list[i].data; + gf_free(audio_data_node->abuf); + gf_free(audio_data_node); + } + } + + dc_circular_buffer_destroy(&audio_input_data->circular_buf); +} + +void dc_audio_inout_data_end_signal(AudioInputData *audio_input_data) +{ + dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf); + dc_producer_end_signal_previous(&audio_input_data->producer, &audio_input_data->circular_buf); +} diff --git a/applications/dashcast/audio_data.h b/applications/dashcast/audio_data.h new file mode 100644 index 0000000..c2b4e35 --- /dev/null +++ b/applications/dashcast/audio_data.h @@ -0,0 +1,142 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef AUDIO_DATA_H_ +#define AUDIO_DATA_H_ + +#define AUDIO_CB_SIZE 3 + +#define LIVE_FRAME_SIZE 1024 +#define MAX_AUDIO_PACKET_SIZE (128 * 1024) + + +#include "../../modules/ffmpeg_in/ffmpeg_in.h" +#include "libavcodec/avcodec.h" +#include "libavutil/mem.h" +#include "libav_compat.h" +#include "circular_buffer.h" + +#include + +//we force the number of channels between the decoder and the encoder: interleaved 16 bits stereo 44100Hz +#define DC_AUDIO_SAMPLE_RATE 44100 +#define DC_AUDIO_NUM_CHANNELS 2 +#define DC_AUDIO_CHANNEL_LAYOUT AV_CH_LAYOUT_STEREO +#define DC_AUDIO_SAMPLE_FORMAT AV_SAMPLE_FMT_S16 + +#define DC_AUDIO_MAX_CHUNCK_SIZE 192000 + + +/* + * AudioInputData is designed to keep the data of input audio in a circular buffer. + * The circular buffer has its own mechanism for synchronization. + */ +typedef struct { + /* The circular buffer of input audio. Input audio is the audio frames after decoding. */ + CircularBuffer circular_buf; + + /* The user of circular buffer has an index to it, which is in this variable. */ + Producer producer; + + AVFrame *aframe; + + int64_t next_pts; + + int channels; + int samplerate; +} AudioInputData; + +/* + * This structure corresponds to an entry of audio configuration in the configuration file + */ +typedef struct { + /* audio file name */ + char filename[GF_MAX_PATH]; + /* audio format */ + char format[GF_MAX_PATH]; + /* audio bitrate */ + int bitrate; + /* audio samplerate */ + int samplerate; + /* audio channel number */ + int channels; + /* audio codec */ + char codec[GF_MAX_PATH]; + /* custom parameter to be passed directly to the encoder - free it once you're done */ + char custom[GF_MAX_PATH]; + + /* used for source switching */ + char source_id[GF_MAX_PATH]; + time_t start_time; + time_t end_time; +} AudioDataConf; + +/* + * Each node in a circular buffer is a pointer. + * To use the circular buffer for audio frame we must + * define the node. AudioDataNode simply contains + * an AVFrame. + */ +typedef struct { + uint8_t *abuf; + int abuf_size; + uint64_t channel_layout; + int sample_rate; + int format; + int channels; +} AudioDataNode; + +void dc_audio_data_set_default(AudioDataConf *audio_data_conf); + +/* + * Initialize an AudioInputData. + * + * @param audio_input_data [out] is the structure to be initialize. + * @param num_consumers [in] contains information on the number of users of circular buffer; + * which means the number of audio encoders. + * @param live [in] indicates the system is live + * + * @return 0 on success, -1 on failure. + * + * @note Must use dc_audio_data_destroy to free memory. + */ +int dc_audio_input_data_init(AudioInputData *audio_input_data, int channels, int samplerate, int num_consumers, int mode); + +/* + * Destroy an AudioInputData + * + * @param audio_input_data [in] the structure to be destroyed. + */ +void dc_audio_input_data_destroy(AudioInputData *audio_input_data); + +/* + * Signal to all the users of the circular buffer in the AudioInputData + * which the current node is the last node to consume. + * + * @param audio_input_data [in] the structure to be signaled on. + */ +void dc_audio_inout_data_end_signal(AudioInputData *audio_input_data); + +#endif /* AUDIO_DATA_H_ */ diff --git a/applications/dashcast/audio_decoder.c b/applications/dashcast/audio_decoder.c new file mode 100644 index 0000000..b5fc1bf --- /dev/null +++ b/applications/dashcast/audio_decoder.c @@ -0,0 +1,399 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "audio_decoder.h" + +int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop) +{ + u32 i; + AVCodecContext *codec_ctx; + AVCodec *codec; + AVInputFormat *in_fmt = NULL; + + if (audio_data_conf->format && strcmp(audio_data_conf->format,"") != 0) { + in_fmt = av_find_input_format(audio_data_conf->format); + if (in_fmt == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", audio_data_conf->format)); + return -1; + } + } + + /* + * Open audio (may already be opened when shared with the video input). + */ + if (!audio_input_file->av_fmt_ctx) { + if (avformat_open_input(&audio_input_file->av_fmt_ctx, audio_data_conf->filename, in_fmt, NULL) != 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file: %s\n", audio_data_conf->filename)); + return -1; + } + + /* + * Retrieve stream information + */ + if (avformat_find_stream_info(audio_input_file->av_fmt_ctx, NULL) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find stream information\n")); + return -1; + } + + av_dump_format(audio_input_file->av_fmt_ctx, 0, audio_data_conf->filename, 0); + } + + /* + * Find the first audio stream + */ + audio_input_file->astream_idx = -1; + for (i=0; iav_fmt_ctx->nb_streams; i++) { + if (audio_input_file->av_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + audio_input_file->astream_idx = i; + break; + } + } + if (audio_input_file->astream_idx == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find a audio stream\n")); + return -1; + } + + /* + * Get a pointer to the codec context for the audio stream + */ + codec_ctx = audio_input_file->av_fmt_ctx->streams[audio_input_file->astream_idx]->codec; + + /* + * Find the decoder for the audio stream + */ + codec = avcodec_find_decoder(codec_ctx->codec_id); + if (codec == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Input audio codec is not supported.\n")); + avformat_close_input(&audio_input_file->av_fmt_ctx); + return -1; + } + + /* + * Open codec + */ + if (avcodec_open2(codec_ctx, codec, NULL) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input audio codec.\n")); + avformat_close_input(&audio_input_file->av_fmt_ctx); + return -1; + } + +#ifdef DC_AUDIO_RESAMPLER + audio_input_file->aresampler = NULL; +#endif + audio_input_file->fifo = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE); + + audio_data_conf->channels = codec_ctx->channels; + audio_data_conf->samplerate = codec_ctx->sample_rate; + + audio_input_file->mode = mode; + audio_input_file->no_loop = no_loop; + + return 0; +} + +#ifdef DC_AUDIO_RESAMPLER +static int ensure_resampler(AudioInputFile *audio_input_file, int sample_rate, int num_channels, u64 channel_layout, enum AVSampleFormat sample_format) +{ + if (!audio_input_file->aresampler) { + audio_input_file->aresampler = avresample_alloc_context(); + if (!audio_input_file->aresampler) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate the audio resampler. Aborting.\n")); + return -1; + } + av_opt_set_int(audio_input_file->aresampler, "in_channel_layout", channel_layout, 0); + av_opt_set_int(audio_input_file->aresampler, "out_channel_layout", DC_AUDIO_CHANNEL_LAYOUT, 0); + av_opt_set_int(audio_input_file->aresampler, "in_sample_fmt", sample_format, 0); + av_opt_set_int(audio_input_file->aresampler, "out_sample_fmt", DC_AUDIO_SAMPLE_FORMAT, 0); + av_opt_set_int(audio_input_file->aresampler, "in_sample_rate", sample_rate, 0); + av_opt_set_int(audio_input_file->aresampler, "out_sample_rate", DC_AUDIO_SAMPLE_RATE, 0); + av_opt_set_int(audio_input_file->aresampler, "in_channels", num_channels, 0); + av_opt_set_int(audio_input_file->aresampler, "out_channels", DC_AUDIO_NUM_CHANNELS, 0); + + if (avresample_open(audio_input_file->aresampler)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not open the audio resampler. Aborting.\n")); + return -1; + } + } + + return 0; +} + +//resample - see http://ffmpeg.org/pipermail/libav-user/2012-June/002164.html +static int resample_audio(AudioInputFile *audio_input_file, AudioInputData *audio_input_data, AVCodecContext *audio_codec_ctx, uint8_t ***output, int *num_planes_out, int num_channels, enum AVSampleFormat sample_format) +{ + int i; + *num_planes_out = av_sample_fmt_is_planar(DC_AUDIO_SAMPLE_FORMAT) ? DC_AUDIO_NUM_CHANNELS : 1; + *output = (uint8_t**)av_malloc(*num_planes_out*sizeof(uint8_t*)); + for (i=0; i<*num_planes_out; i++) { + (*output) [i] = (uint8_t*)av_malloc(DC_AUDIO_MAX_CHUNCK_SIZE); //FIXME: fix using size below av_samples_get_buffer_size() + } + + i = avresample_convert(audio_input_file->aresampler, *output, DC_AUDIO_MAX_CHUNCK_SIZE, audio_input_data->aframe->nb_samples, audio_input_data->aframe->extended_data, audio_input_data->aframe->linesize[0], audio_input_data->aframe->nb_samples); + if (i < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not resample audio frame. Aborting.\n")); + return -1; + } + + return i; +} +#endif + +int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audio_input_data) +{ + int ret; + AVPacket packet; + int got_frame = 0; + AVCodecContext *codec_ctx; + AudioDataNode *audio_data_node; + + /* Get a pointer to the codec context for the audio stream */ + codec_ctx = audio_input_file->av_fmt_ctx->streams[audio_input_file->astream_idx]->codec; + + /* Read frames */ + while (1) { + if (audio_input_file->av_pkt_list) { + if (gf_list_count(audio_input_file->av_pkt_list)) { + AVPacket *packet_copy; + assert(audio_input_file->av_pkt_list); + gf_mx_p(audio_input_file->av_pkt_list_mutex); + packet_copy = gf_list_pop_front(audio_input_file->av_pkt_list); + gf_mx_v(audio_input_file->av_pkt_list_mutex); + + if (packet_copy == NULL) { + ret = AVERROR_EOF; + } else { + memcpy(&packet, packet_copy, sizeof(AVPacket)); + gf_free(packet_copy); + ret = 0; + } + } else { + gf_sleep(1); + continue; + } + } else { + ret = av_read_frame(audio_input_file->av_fmt_ctx, &packet); + } + if (ret == AVERROR_EOF) { + if (audio_input_file->mode == LIVE_MEDIA && audio_input_file->no_loop == 0) { + av_seek_frame(audio_input_file->av_fmt_ctx, audio_input_file->astream_idx, 0, 0); + continue; + } + + /* Flush decoder */ + packet.data = NULL; + packet.size = 0; + +#ifndef FF_API_AVFRAME_LAVC + avcodec_get_frame_defaults(audio_input_data->aframe); +#else + av_frame_unref(audio_input_data->aframe); +#endif + + avcodec_decode_audio4(codec_ctx, audio_input_data->aframe, &got_frame, &packet); + + if (got_frame) { + dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf); + dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf); + audio_data_node = (AudioDataNode*)dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf); + + audio_data_node->abuf_size = audio_input_data->aframe->linesize[0]; + memcpy(audio_data_node->abuf, audio_input_data->aframe->data[0], audio_data_node->abuf_size); + + dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf); + return 0; + } + + dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf); + dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf); + + return -2; + } + else if (ret < 0) + { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot read audio frame.\n")); + continue; + } + + /* Is this a packet from the audio stream? */ + if (packet.stream_index == audio_input_file->astream_idx) { + /* Set audio frame to default */ + +#ifndef FF_API_AVFRAME_LAVC + avcodec_get_frame_defaults(audio_input_data->aframe); +#else + av_frame_unref(audio_input_data->aframe); +#endif + + /* Decode audio frame */ + if (avcodec_decode_audio4(codec_ctx, audio_input_data->aframe, &got_frame, &packet) < 0) { + av_free_packet(&packet); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while decoding audio.\n")); + dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf); + dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf); + return -1; + } + + if (audio_input_data->aframe->pts != AV_NOPTS_VALUE) + audio_input_data->next_pts = audio_input_data->aframe->pts; + + audio_input_data->next_pts += ((int64_t)AV_TIME_BASE * audio_input_data->aframe->nb_samples) / codec_ctx->sample_rate; + + /* Did we get an audio frame? */ + if (got_frame) { + uint8_t **data; + int data_size; +#ifdef DC_AUDIO_RESAMPLER + int num_planes_out; +#endif +#ifdef GPAC_USE_LIBAV + int sample_rate = codec_ctx->sample_rate; + int num_channels = codec_ctx->channels; + u64 channel_layout = codec_ctx->channel_layout; +#else + int sample_rate = audio_input_data->aframe->sample_rate; + int num_channels = audio_input_data->aframe->channels; + u64 channel_layout = audio_input_data->aframe->channel_layout; +#endif + enum AVSampleFormat sample_format = (enum AVSampleFormat)audio_input_data->aframe->format; + Bool resample = (sample_rate != DC_AUDIO_SAMPLE_RATE + || num_channels != DC_AUDIO_NUM_CHANNELS + || channel_layout != DC_AUDIO_CHANNEL_LAYOUT + || sample_format != DC_AUDIO_SAMPLE_FORMAT); + + /* Resample if needed */ + if (resample) { +#ifndef DC_AUDIO_RESAMPLER + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio resampling is needed at the decoding stage, but not supported by your version of DashCast. Aborting.\n")); + exit(1); +#else + uint8_t **output; + int nb_samp; + if (ensure_resampler(audio_input_file, sample_rate, num_channels, channel_layout, sample_format)) { + return -1; + } + + nb_samp = resample_audio(audio_input_file, audio_input_data, codec_ctx, &output, &num_planes_out, num_channels, sample_format); + if (nb_samp<0) { + return -1; + } + + av_samples_get_buffer_size(&data_size, DC_AUDIO_NUM_CHANNELS, nb_samp, DC_AUDIO_SAMPLE_FORMAT, 0); + data = output; +#endif + } else { + /*no resampling needed: read data from the AVFrame*/ + data = audio_input_data->aframe->extended_data; + data_size = audio_input_data->aframe->linesize[0]; + } + + assert(!av_sample_fmt_is_planar(DC_AUDIO_SAMPLE_FORMAT)); + av_fifo_generic_write(audio_input_file->fifo, data[0], data_size, NULL); + + if (/*audio_input_file->circular_buf.mode == OFFLINE*/audio_input_file->mode == ON_DEMAND || audio_input_file->mode == LIVE_MEDIA) { + dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf); + + /* Unlock the previous node in the circular buffer. */ + dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf); + + /* Get the pointer of the current node in circular buffer. */ + audio_data_node = (AudioDataNode *) dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf); + audio_data_node->channels = DC_AUDIO_NUM_CHANNELS; + audio_data_node->channel_layout = DC_AUDIO_CHANNEL_LAYOUT; + audio_data_node->sample_rate = DC_AUDIO_SAMPLE_RATE; + audio_data_node->format = DC_AUDIO_SAMPLE_FORMAT; + audio_data_node->abuf_size = data_size; + av_fifo_generic_read(audio_input_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL); + + dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf); + } else { + while (av_fifo_size(audio_input_file->fifo) >= LIVE_FRAME_SIZE) { + /* Lock the current node in the circular buffer. */ + if (dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped an audio frame\n")); + continue; + } + + /* Unlock the previous node in the circular buffer. */ + dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf); + + /* Get the pointer of the current node in circular buffer. */ + audio_data_node = (AudioDataNode *) dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf); + + audio_data_node->abuf_size = LIVE_FRAME_SIZE; + av_fifo_generic_read(audio_input_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL); + + dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf); + } + } + +#ifdef DC_AUDIO_RESAMPLER + if (resample) { + int i; + for (i=0; iav_fmt_ctx); + + if (audio_input_file->av_pkt_list_mutex) { + gf_mx_p(audio_input_file->av_pkt_list_mutex); + while (gf_list_count(audio_input_file->av_pkt_list)) { + AVPacket *pkt = gf_list_last(audio_input_file->av_pkt_list); + av_free_packet(pkt); + gf_list_rem_last(audio_input_file->av_pkt_list); + } + gf_list_del(audio_input_file->av_pkt_list); + gf_mx_v(audio_input_file->av_pkt_list_mutex); + gf_mx_del(audio_input_file->av_pkt_list_mutex); + } + + av_fifo_free(audio_input_file->fifo); + +#ifdef DC_AUDIO_RESAMPLER + avresample_free(&audio_input_file->aresampler); +#endif +} diff --git a/applications/dashcast/audio_decoder.h b/applications/dashcast/audio_decoder.h new file mode 100644 index 0000000..db094fb --- /dev/null +++ b/applications/dashcast/audio_decoder.h @@ -0,0 +1,100 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef AUDIO_DECODER_H_ +#define AUDIO_DECODER_H_ + +#include "audio_data.h" + +#include "libavformat/avformat.h" +#include "libavutil/fifo.h" +#ifdef DC_AUDIO_RESAMPLER +#include "libavutil/opt.h" +#include "libavresample/avresample.h" +#endif + + +/* + * The structure which keeps the data of + * input audio file. + */ +typedef struct { + /* Format context structure provided by avlib to open and read from a media file. */ + AVFormatContext *av_fmt_ctx; + + /* A list of AVPackets and return value to be processed: when this parameter is non-null, + * the video thread makes the demux and pushes the packets. */ + GF_List *av_pkt_list; + GF_Mutex *av_pkt_list_mutex; + + /* The index of the audio stream in the file. */ + int astream_idx; + + /* This is the output FIFO linking the decoder to the other encoder: only conveys + * stereo 44100 (and resample if needed) */ + AVFifoBuffer *fifo; +#ifdef DC_AUDIO_RESAMPLER + /* Optional audio resampling between the decoder and the encoder */ + AVAudioResampleContext *aresampler; +#endif + + LockMode mode; + int no_loop; +} AudioInputFile; + +/* + * Open the input audio + * + * @param cmd_data [in] contains information about the file name + * and the audio format. + * + * @param audio_input_file [out] pointer to the structure which we want to + * open the file + * + * @return 0 on success -1 on failure. + */ +int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop); + +/* + * Read and decode audio and put samples on circular buffer + * + * @param audio_input_file [in] contains info on input audio. This parameter + * must have been opened with open_audio_input + * + * @param audio_input_data [out] the samples will be saved on the circular buffer + * of this parameter. + * + * @return 0 on success, -1 on failure, -2 on EOF (end of the file) + */ +int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audio_input_data); + +/* + * Close the input audio + * + * @param audio_input_file [in] the audio file to be closed + */ +void dc_audio_decoder_close(AudioInputFile *audio_input_file); + +#endif /* AUDIO_DECODER_H_ */ diff --git a/applications/dashcast/audio_encoder.c b/applications/dashcast/audio_encoder.c new file mode 100644 index 0000000..c0d6a79 --- /dev/null +++ b/applications/dashcast/audio_encoder.c @@ -0,0 +1,347 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "audio_encoder.h" + + +extern void build_dict(void *priv_data, const char *options); + + +int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf) +{ + AVDictionary *opts = NULL; + + audio_output_file->fifo = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE); + audio_output_file->aframe = FF_ALLOC_FRAME(); + audio_output_file->adata_buf = (uint8_t*) av_malloc(2 * MAX_AUDIO_PACKET_SIZE); +#ifndef GPAC_USE_LIBAV + audio_output_file->aframe->channels = -1; +#endif +#ifndef LIBAV_FRAME_OLD + audio_output_file->aframe->channel_layout = 0; + audio_output_file->aframe->sample_rate = -1; +#endif + audio_output_file->aframe->format = -1; + audio_output_file->codec = avcodec_find_encoder_by_name(audio_data_conf->codec); + if (audio_output_file->codec == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output audio codec not found\n")); + return -1; + } + + audio_output_file->codec_ctx = avcodec_alloc_context3(audio_output_file->codec); + audio_output_file->codec_ctx->codec_id = audio_output_file->codec->id; + audio_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_AUDIO; + audio_output_file->codec_ctx->bit_rate = audio_data_conf->bitrate; + audio_output_file->codec_ctx->sample_rate = DC_AUDIO_SAMPLE_RATE /*audio_data_conf->samplerate*/; + + { + AVRational time_base; + time_base.num = 1; + time_base.den = audio_output_file->codec_ctx->sample_rate; + audio_output_file->codec_ctx->time_base = time_base; + } + audio_output_file->codec_ctx->channels = audio_data_conf->channels; + audio_output_file->codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; /*FIXME: depends on channels -> http://ffmpeg.org/doxygen/trunk/channel__layout_8c_source.html#l00074*/ + audio_output_file->codec_ctx->sample_fmt = audio_output_file->codec->sample_fmts[0]; +#ifdef DC_AUDIO_RESAMPLER + audio_output_file->aresampler = NULL; +#endif + if (audio_data_conf->custom) { + build_dict(audio_output_file->codec_ctx->priv_data, audio_data_conf->custom); + } + audio_output_file->astream_idx = 0; + + /* open the audio codec */ + av_dict_set(&opts, "strict", "experimental", 0); + if (avcodec_open2(audio_output_file->codec_ctx, audio_output_file->codec, &opts) < 0) { + /*FIXME: if we enter here (set "mp2" as a codec and "200000" as a bitrate -> deadlock*/ + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio codec\n")); + av_dict_free(&opts); + return -1; + } + av_dict_free(&opts); + + audio_output_file->frame_bytes = audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(DC_AUDIO_SAMPLE_FORMAT) * DC_AUDIO_NUM_CHANNELS; + +#ifndef FF_API_AVFRAME_LAVC + avcodec_get_frame_defaults(audio_output_file->aframe); +#else + av_frame_unref(audio_output_file->aframe); +#endif + + + audio_output_file->aframe->nb_samples = audio_output_file->codec_ctx->frame_size; + + if (avcodec_fill_audio_frame(audio_output_file->aframe, audio_output_file->codec_ctx->channels, audio_output_file->codec_ctx->sample_fmt, + audio_output_file->adata_buf, audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * audio_output_file->codec_ctx->channels, 1) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Fill audio frame failed\n")); + return -1; + } + + //audio_output_file->acc_samples = 0; + + return 0; +} + +int dc_audio_encoder_read(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data) +{ + int ret; + AudioDataNode *audio_data_node; + + ret = dc_consumer_lock(&audio_output_file->consumer, &audio_input_data->circular_buf); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio encoder got an end of buffer!\n")); + return -2; + } + + dc_consumer_unlock_previous(&audio_output_file->consumer, &audio_input_data->circular_buf); + + audio_data_node = (AudioDataNode *) dc_consumer_consume(&audio_output_file->consumer, &audio_input_data->circular_buf); +#ifndef GPAC_USE_LIBAV + audio_output_file->aframe->channels = audio_output_file->codec_ctx->channels; +#endif +#ifndef LIBAV_FRAME_OLD + audio_output_file->aframe->channel_layout = audio_output_file->codec_ctx->channel_layout; + audio_output_file->aframe->sample_rate = audio_output_file->codec_ctx->sample_rate; +#endif + audio_output_file->aframe->format = audio_output_file->codec_ctx->sample_fmt; + + /* Write audio sample on fifo */ + av_fifo_generic_write(audio_output_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL); + + dc_consumer_advance(&audio_output_file->consumer); + + return 0; +} + +#if 0 +int dc_audio_encoder_flush(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data) +{ + int got_pkt; + //AVStream *audio_stream = audio_output_file->av_fmt_ctx->streams[audio_output_file->astream_idx]; + //AVCodecContext *audio_codec_ctx = audio_stream->codec; + AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx; + + av_init_packet(&audio_output_file->packet); + audio_output_file->packet.data = NULL; + audio_output_file->packet.size = 0; + + /* Set PTS (method 1) */ + audio_output_file->aframe->pts = audio_input_data->next_pts; + /* Encode audio */ +#ifdef DC_AUDIO_RESAMPLER +#error resampling is not done here +#endif + if (avcodec_encode_audio2(audio_codec_ctx, &audio_output_file->packet, NULL, &got_pkt) != 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while encoding audio.\n")); + return -1; + } + if (got_pkt) { + //audio_output_file->acc_samples += audio_output_file->aframe->nb_samples; + return 0; + } + av_free_packet(&audio_output_file->packet); + return 1; +} +#endif + +#ifdef DC_AUDIO_RESAMPLER +static int ensure_resampler(AudioOutputFile *audio_output_file, AVCodecContext *audio_codec_ctx) +{ + if (!audio_output_file->aresampler) { + audio_output_file->aresampler = avresample_alloc_context(); + if (!audio_output_file->aresampler) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate the audio resampler. Aborting.\n")); + return -1; + } + av_opt_set_int(audio_output_file->aresampler, "in_channel_layout", DC_AUDIO_CHANNEL_LAYOUT, 0); + av_opt_set_int(audio_output_file->aresampler, "out_channel_layout", audio_codec_ctx->channel_layout, 0); + av_opt_set_int(audio_output_file->aresampler, "in_sample_fmt", DC_AUDIO_SAMPLE_FORMAT, 0); + av_opt_set_int(audio_output_file->aresampler, "out_sample_fmt", audio_codec_ctx->sample_fmt, 0); + av_opt_set_int(audio_output_file->aresampler, "in_sample_rate", DC_AUDIO_SAMPLE_RATE, 0); + av_opt_set_int(audio_output_file->aresampler, "out_sample_rate", audio_codec_ctx->sample_rate, 0); + av_opt_set_int(audio_output_file->aresampler, "in_channels", DC_AUDIO_NUM_CHANNELS, 0); + av_opt_set_int(audio_output_file->aresampler, "out_channels", audio_codec_ctx->channels, 0); + + if (avresample_open(audio_output_file->aresampler)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not open the audio resampler. Aborting.\n")); + return -1; + } + } + + return 0; +} + +//resample - see http://ffmpeg.org/pipermail/libav-user/2012-June/002164.html +static int resample_audio(AudioOutputFile *audio_output_file, AVCodecContext *audio_codec_ctx, int *num_planes_out) +{ + int i, linesize; + uint8_t **output; + *num_planes_out = av_sample_fmt_is_planar(audio_output_file->codec->sample_fmts[0]) ? audio_output_file->codec_ctx->channels : 1; + linesize = audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(audio_output_file->codec->sample_fmts[0]) * audio_output_file->codec_ctx->channels / *num_planes_out; + output = (uint8_t**)av_malloc(*num_planes_out*sizeof(uint8_t*)); + for (i=0; i<*num_planes_out; i++) { + output[i] = (uint8_t*)av_malloc(linesize); + } + + if (avresample_convert(audio_output_file->aresampler, output, linesize, audio_output_file->aframe->nb_samples, audio_output_file->aframe->extended_data, audio_output_file->aframe->linesize[0], audio_output_file->aframe->nb_samples) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not resample audio frame. Aborting.\n")); + return -1; + } + + audio_output_file->aframe->extended_data = output; + for (i=0; i<*num_planes_out; i++) { + audio_output_file->aframe->linesize[i] = linesize; + } + audio_codec_ctx->channel_layout = audio_output_file->aframe->channel_layout; + audio_codec_ctx->sample_fmt = audio_output_file->aframe->format; + audio_codec_ctx->sample_rate = audio_output_file->aframe->sample_rate; +#ifndef GPAC_USE_LIBAV + audio_codec_ctx->channels = audio_output_file->aframe->channels; +#endif + + return 0; +} +#endif + +int dc_audio_encoder_encode(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data) +{ + int got_pkt; + AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx; + + while (av_fifo_size(audio_output_file->fifo) >= audio_output_file->frame_bytes) { +#ifdef DC_AUDIO_RESAMPLER + uint8_t **data; //mirror AVFrame::data + int num_planes_out; +#endif + Bool resample; + + av_fifo_generic_read(audio_output_file->fifo, audio_output_file->adata_buf, audio_output_file->frame_bytes, NULL); + + audio_output_file->aframe->data[0] = audio_output_file->adata_buf; + audio_output_file->aframe->linesize[0] = audio_output_file->frame_bytes; + audio_output_file->aframe->linesize[1] = 0; + + av_init_packet(&audio_output_file->packet); + audio_output_file->packet.data = NULL; + audio_output_file->packet.size = 0; + + /* + * Set PTS (method 1) + */ + //audio_output_file->aframe->pts = audio_input_data->next_pts; + + /* + * Set PTS (method 2) + */ + //{ + // int64_t now = av_gettime(); + // AVRational avr; + // avr.num = 1; + // avr.den = AV_TIME_BASE; + // audio_output_file->aframe->pts = av_rescale_q(now, avr, audio_codec_ctx->time_base); + //} + + resample = (DC_AUDIO_SAMPLE_FORMAT != audio_codec_ctx->sample_fmt + || DC_AUDIO_SAMPLE_RATE != audio_codec_ctx->sample_rate + || DC_AUDIO_NUM_CHANNELS != audio_codec_ctx->channels + || DC_AUDIO_CHANNEL_LAYOUT != audio_codec_ctx->channel_layout); + /* Resample if needed */ + if (resample) { +#ifndef DC_AUDIO_RESAMPLER + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio resampling is needed at the encoding stage, but not supported by your version of DashCast. Aborting.\n")); + exit(1); +#else + if (ensure_resampler(audio_output_file, audio_codec_ctx)) { + return -1; + } + + data = audio_output_file->aframe->extended_data; + if (resample_audio(audio_output_file, audio_codec_ctx, &num_planes_out)) { + return -1; + } +#endif + } + + /* Encode audio */ + if (avcodec_encode_audio2(audio_codec_ctx, &audio_output_file->packet, audio_output_file->aframe, &got_pkt) != 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while encoding audio.\n")); +#ifdef DC_AUDIO_RESAMPLER + if (resample) { + int i; + for (i=0; iaframe->extended_data[i]); + } + av_free(audio_output_file->aframe->extended_data); + audio_output_file->aframe->extended_data = data; + } +#endif + return -1; + } + +#ifdef DC_AUDIO_RESAMPLER + if (resample) { + int i; + for (i=0; iaframe->extended_data[i]); + } + av_free(audio_output_file->aframe->extended_data); + audio_output_file->aframe->extended_data = data; + } +#endif + + if (got_pkt) { + //audio_output_file->acc_samples += audio_output_file->aframe->nb_samples; + return 0; + } + + av_free_packet(&audio_output_file->packet); + } + + return 1; +} + +void dc_audio_encoder_close(AudioOutputFile *audio_output_file) +{ +// int i; +// +// /* free the streams */ +// for (i = 0; i < audio_output_file->av_fmt_ctx->nb_streams; i++) { +// avcodec_close(audio_output_file->av_fmt_ctx->streams[i]->codec); +// av_freep(&audio_output_file->av_fmt_ctx->streams[i]->info); +// } + + av_fifo_free(audio_output_file->fifo); + + av_free(audio_output_file->adata_buf); + av_free(audio_output_file->aframe); + + avcodec_close(audio_output_file->codec_ctx); + av_free(audio_output_file->codec_ctx); + +#ifdef DC_AUDIO_RESAMPLER + avresample_free(&audio_output_file->aresampler); +#endif +} diff --git a/applications/dashcast/audio_encoder.h b/applications/dashcast/audio_encoder.h new file mode 100644 index 0000000..b8fbd3d --- /dev/null +++ b/applications/dashcast/audio_encoder.h @@ -0,0 +1,64 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef AUDIO_ENCODER_H_ +#define AUDIO_ENCODER_H_ + +#include "audio_muxer.h" + +/* + * Open an audio stream + * + * @param audio_output_file [in] add an audio stream to the file + * with the parameters already passed to open_audio_output + * + * @return 0 on success, -1 on failure + */ +int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf); + +int dc_audio_encoder_read(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data); + +//int dc_audio_encoder_flush(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data); + +/* + * Read the decoded audio sample from circular buffer (which is in audio_input_data) + * and encode and write them on the output file + * + * @param audio_output_file [in] audio output file + * @param audio_input_data [in] audio input data structure which contains a circular buffer with audio samples + * + * @return 0 on success, -1 on failure, -2 on finishing; + * when there is no more data on circular buffer to encode + */ +int dc_audio_encoder_encode(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data); + +/* + * Close the output audio file + * + * @param audio_output_file [in] audio output file + */ +void dc_audio_encoder_close(AudioOutputFile *audio_output_file); + +#endif /* AUDIO_ENCODER_H_ */ diff --git a/applications/dashcast/audio_muxer.c b/applications/dashcast/audio_muxer.c new file mode 100644 index 0000000..50ae59e --- /dev/null +++ b/applications/dashcast/audio_muxer.c @@ -0,0 +1,462 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "audio_muxer.h" +#include "libavformat/avio.h" + +#ifndef GPAC_DISABLE_ISOM + +int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename) +{ + GF_Err ret; + u32 di, track; + u8 bpsample; + GF_ESD *esd; +#ifndef GPAC_DISABLE_AV_PARSERS + GF_M4ADecSpecInfo acfg; +#endif + AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx; + + audio_output_file->isof = gf_isom_open(filename, GF_ISOM_OPEN_WRITE, NULL); + if (!audio_output_file->isof) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open iso file %s\n", filename)); + return -1; + } + + esd = gf_odf_desc_esd_new(2); + if (!esd) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create GF_ESD\n")); + return -1; + } + + esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); + esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); + esd->decoderConfig->streamType = GF_STREAM_AUDIO; + if (!strcmp(audio_output_file->codec_ctx->codec->name, "aac")) { //TODO: find an automatic table + esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG2_LCP; + esd->decoderConfig->bufferSizeDB = 20; + esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate; + esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); + esd->ESID = 1; + +#ifndef GPAC_DISABLE_AV_PARSERS + memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo)); + acfg.base_object_type = GF_M4A_AAC_LC; + acfg.base_sr = audio_codec_ctx->sample_rate; + acfg.nb_chan = audio_codec_ctx->channels; + acfg.sbr_object_type = 0; + acfg.audioPL = gf_m4a_get_profile(&acfg); + + ret = gf_m4a_write_config(&acfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); + assert(ret == GF_OK); +#endif + } else { + if (strcmp(audio_output_file->codec_ctx->codec->name, "mp2")) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Unlisted codec, setting GPAC_OTI_AUDIO_MPEG1 descriptor.\n")); + } + esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1; + esd->decoderConfig->bufferSizeDB = 20; + esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate; + esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); + esd->ESID = 1; + +#ifndef GPAC_DISABLE_AV_PARSERS + memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo)); + acfg.base_object_type = GF_M4A_LAYER2; + acfg.base_sr = audio_codec_ctx->sample_rate; + acfg.nb_chan = audio_codec_ctx->channels; + acfg.sbr_object_type = 0; + acfg.audioPL = gf_m4a_get_profile(&acfg); + + ret = gf_m4a_write_config(&acfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); + assert(ret == GF_OK); +#endif + } + + //gf_isom_store_movie_config(video_output_file->isof, 0); + track = gf_isom_new_track(audio_output_file->isof, esd->ESID, GF_ISOM_MEDIA_AUDIO, audio_codec_ctx->sample_rate); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("TimeScale: %d \n", audio_codec_ctx->time_base.den)); + if (!track) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create new track\n")); + return -1; + } + + ret = gf_isom_set_track_enabled(audio_output_file->isof, track, 1); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_track_enabled\n", gf_error_to_string(ret))); + return -1; + } + +// if (!esd->ESID) esd->ESID = gf_isom_get_track_id(audio_output_file->isof, track); + + ret = gf_isom_new_mpeg4_description(audio_output_file->isof, track, esd, NULL, NULL, &di); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_new_mpeg4_description\n", gf_error_to_string(ret))); + return -1; + } + + gf_odf_desc_del((GF_Descriptor *) esd); + esd = NULL; + + bpsample = av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * 8; + + ret = gf_isom_set_audio_info(audio_output_file->isof, track, di, audio_codec_ctx->sample_rate, audio_output_file->codec_ctx->channels, bpsample); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_audio_info\n", gf_error_to_string(ret))); + return -1; + } + +#ifndef GPAC_DISABLE_AV_PARSERS + ret = gf_isom_set_pl_indication(audio_output_file->isof, GF_ISOM_PL_AUDIO, acfg.audioPL); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_pl_indication\n", gf_error_to_string(ret))); + return -1; + } +#endif + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("time scale: %d sample dur: %d \n", audio_codec_ctx->time_base.den, audio_output_file->codec_ctx->frame_size)); + + ret = gf_isom_setup_track_fragment(audio_output_file->isof, track, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0, 0); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_setup_track_fragment\n", gf_error_to_string(ret))); + return -1; + } + + //gf_isom_add_track_to_root_od(video_output_file->isof,1); + + ret = gf_isom_finalize_for_fragment(audio_output_file->isof, 1); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret))); + return -1; + } + + return 0; +} + +int dc_gpac_audio_isom_open_seg(AudioOutputFile *audio_output_file, char *filename) +{ + GF_Err ret; + ret = gf_isom_start_segment(audio_output_file->isof, filename, GF_TRUE); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_start_segment\n", gf_error_to_string(ret))); + return -1; + } + + audio_output_file->dts = 0; + + return 0; +} + +int dc_gpac_audio_isom_write(AudioOutputFile *audio_output_file) +{ + GF_Err ret; + audio_output_file->sample->data = (char *) audio_output_file->packet.data; + audio_output_file->sample->dataLength = audio_output_file->packet.size; + + audio_output_file->sample->DTS = audio_output_file->dts; //audio_output_file->aframe->pts; + audio_output_file->sample->IsRAP = RAP; //audio_output_file->aframe->key_frame;//audio_codec_ctx->coded_frame->key_frame; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("RAP %d , DTS %ld \n", audio_output_file->sample->IsRAP, audio_output_file->sample->DTS)); + + ret = gf_isom_fragment_add_sample(audio_output_file->isof, 1, audio_output_file->sample, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0); + audio_output_file->dts += audio_output_file->codec_ctx->frame_size; + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_fragment_add_sample\n", gf_error_to_string(ret))); + return -1; + } + +// ret = gf_isom_flush_fragments(video_output_file->isof, 1); +// if (ret != GF_OK) { +// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_flush_fragments\n", gf_error_to_string(ret))); +// return -1; +// } + + return 0; +} + +int dc_gpac_audio_isom_close_seg(AudioOutputFile *audio_output_file) +{ + GF_Err ret; + ret = gf_isom_close_segment(audio_output_file->isof, 0, 0,0, 0, 0, 0, 1, audio_output_file->seg_marker, NULL, NULL); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close_segment\n", gf_error_to_string(ret))); + return -1; + } + + //audio_output_file->acc_samples = 0; + + return 0; +} + +int dc_gpac_audio_isom_close(AudioOutputFile *audio_output_file) +{ + GF_Err ret; + ret = gf_isom_close(audio_output_file->isof); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close\n", gf_error_to_string(ret))); + return -1; + } + + //audio_output_file->acc_samples = 0; + + return 0; +} + +#endif + + + +int dc_ffmpeg_audio_muxer_open(AudioOutputFile *audio_output_file, char *filename) +{ + AVStream *audio_stream; + AVOutputFormat *output_fmt; + AVDictionary *opts = NULL; + + AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx; + audio_output_file->av_fmt_ctx = NULL; + +// strcpy(audio_output_file->filename, audio_data_conf->filename); +// audio_output_file->abr = audio_data_conf->bitrate; +// audio_output_file->asr = audio_data_conf->samplerate; +// audio_output_file->ach = audio_data_conf->channels; +// strcpy(audio_output_file->codec, audio_data_conf->codec); + + /* Find output format */ + output_fmt = av_guess_format(NULL, filename, NULL); + if (!output_fmt) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find suitable output format\n")); + return -1; + } + + audio_output_file->av_fmt_ctx = avformat_alloc_context(); + if (!audio_output_file->av_fmt_ctx) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate memory for pOutVideoFormatCtx\n")); + return -1; + } + + audio_output_file->av_fmt_ctx->oformat = output_fmt; + strcpy(audio_output_file->av_fmt_ctx->filename, filename); + + /* Open the output file */ + if (!(output_fmt->flags & AVFMT_NOFILE)) { + if (avio_open(&audio_output_file->av_fmt_ctx->pb, filename, URL_WRONLY) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot not open '%s'\n", filename)); + return -1; + } + } + + audio_stream = avformat_new_stream(audio_output_file->av_fmt_ctx, audio_output_file->codec); + if (!audio_stream) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create output video stream\n")); + return -1; + } + + audio_stream->codec->codec_id = audio_output_file->codec->id; + audio_stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; + audio_stream->codec->bit_rate = audio_codec_ctx->bit_rate;//audio_output_file->audio_data_conf->bitrate; + audio_stream->codec->sample_rate = audio_codec_ctx->sample_rate;//audio_output_file->audio_data_conf->samplerate; + audio_stream->codec->channels = audio_codec_ctx->channels;//audio_output_file->audio_data_conf->channels; + assert(audio_codec_ctx->codec->sample_fmts); + audio_stream->codec->sample_fmt = audio_codec_ctx->codec->sample_fmts[0]; + +// if (audio_output_file->av_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) +// audio_output_file->codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + + //video_stream->codec = video_output_file->codec_ctx; + + /* open the video codec */ + av_dict_set(&opts, "strict", "experimental", 0); + if (avcodec_open2(audio_stream->codec, audio_output_file->codec, &opts) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n")); + av_dict_free(&opts); + return -1; + } + av_dict_free(&opts); + + avformat_write_header(audio_output_file->av_fmt_ctx, NULL); + + return 0; +} + +int dc_ffmpeg_audio_muxer_write(AudioOutputFile *audio_output_file) +{ + AVStream *audio_stream = audio_output_file->av_fmt_ctx->streams[audio_output_file->astream_idx]; + AVCodecContext *audio_codec_ctx = audio_stream->codec; + + audio_output_file->packet.stream_index = audio_stream->index; + + if (audio_output_file->packet.pts != AV_NOPTS_VALUE) + audio_output_file->packet.pts = av_rescale_q(audio_output_file->packet.pts, audio_codec_ctx->time_base, audio_stream->time_base); + + if (audio_output_file->packet.duration > 0) + audio_output_file->packet.duration = (int)av_rescale_q(audio_output_file->packet.duration, audio_codec_ctx->time_base, audio_stream->time_base); + /* + * if (pkt.pts != AV_NOPTS_VALUE) + * pkt.pts = av_rescale_q(pkt.pts, audioEncCtx->time_base, audioStream->time_base); + */ + + audio_output_file->packet.flags |= AV_PKT_FLAG_KEY; + + if (av_interleaved_write_frame(audio_output_file->av_fmt_ctx, &audio_output_file->packet) != 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Writing frame is not successful\n")); + av_free_packet(&audio_output_file->packet); + return -1; + } + + av_free_packet(&audio_output_file->packet); + + return 0; +} + +int dc_ffmpeg_audio_muxer_close(AudioOutputFile *audio_output_file) +{ + u32 i; + + av_write_trailer(audio_output_file->av_fmt_ctx); + avio_close(audio_output_file->av_fmt_ctx->pb); + + // free the streams + for (i = 0; i < audio_output_file->av_fmt_ctx->nb_streams; i++) { + avcodec_close(audio_output_file->av_fmt_ctx->streams[i]->codec); + av_freep(&audio_output_file->av_fmt_ctx->streams[i]->info); + } + + //video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx]->codec = NULL; + avformat_free_context(audio_output_file->av_fmt_ctx); + + //audio_output_file->acc_samples = 0; + + return 0; + +} + +int dc_audio_muxer_init(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf, AudioMuxerType muxer_type, int frame_per_seg, int frame_per_frag, u32 seg_marker) +{ + char name[GF_MAX_PATH]; + snprintf(name, sizeof(name), "audio encoder %s", audio_data_conf->filename); + dc_consumer_init(&audio_output_file->consumer, AUDIO_CB_SIZE, name); + +#ifndef GPAC_DISABLE_ISOM + audio_output_file->sample = gf_isom_sample_new(); + audio_output_file->isof = NULL; +#endif + + audio_output_file->muxer_type = muxer_type; + audio_output_file->frame_per_seg = frame_per_seg; + audio_output_file->frame_per_frag = frame_per_frag; + audio_output_file->seg_marker = seg_marker; + return 0; +} + +void dc_audio_muxer_free(AudioOutputFile *audio_output_file) +{ +#ifndef GPAC_DISABLE_ISOM + if (audio_output_file->isof != NULL) { + gf_isom_close(audio_output_file->isof); + } + //gf_isom_sample_del(&audio_output_file->sample); +#endif +} + +GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, char *id_name, int seg) +{ + GF_Err ret = GF_NOT_SUPPORTED; + char name[GF_MAX_PATH]; + + switch (audio_output_file->muxer_type) { + case FFMPEG_AUDIO_MUXER: + snprintf(name, sizeof(name), "%s/%s_%d_ffmpeg.mp4", directory, id_name, seg); + return dc_ffmpeg_audio_muxer_open(audio_output_file, name); +#ifndef GPAC_DISABLE_ISOM + case GPAC_AUDIO_MUXER: + snprintf(name, sizeof(name), "%s/%s_%d_gpac.mp4", directory, id_name, seg); + dc_gpac_audio_moov_create(audio_output_file, name); + return dc_gpac_audio_isom_open_seg(audio_output_file, NULL); + case GPAC_INIT_AUDIO_MUXER: + if (seg == 1) { + snprintf(name, sizeof(name), "%s/%s_init_gpac.mp4", directory, id_name); + dc_gpac_audio_moov_create(audio_output_file, name); + audio_output_file->first_dts = 0; + } + snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg); + ret = dc_gpac_audio_isom_open_seg(audio_output_file, name); + return ret; +#endif + default: + ret = GF_BAD_PARAM; + break; + } + + return ret; +} + +int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb) +{ + switch (audio_output_file->muxer_type) { + case FFMPEG_AUDIO_MUXER: + return dc_ffmpeg_audio_muxer_write(audio_output_file); +#ifndef GPAC_DISABLE_ISOM + case GPAC_AUDIO_MUXER: + case GPAC_INIT_AUDIO_MUXER: + if (frame_nb % audio_output_file->frame_per_frag == 0) { + gf_isom_start_fragment(audio_output_file->isof, 1); + gf_isom_set_traf_base_media_decode_time(audio_output_file->isof, 1, audio_output_file->first_dts * audio_output_file->codec_ctx->frame_size); + audio_output_file->first_dts += audio_output_file->frame_per_frag; + } + dc_gpac_audio_isom_write(audio_output_file); + if (frame_nb % audio_output_file->frame_per_frag == audio_output_file->frame_per_frag - 1) { + gf_isom_flush_fragments(audio_output_file->isof, 1); + } + //TODO - do same as video, flush based on time in case of losses + if (frame_nb + 1 == audio_output_file->frame_per_seg) { + return 1; + } + + return 0; +#endif + + default: + return GF_BAD_PARAM; + } + return GF_BAD_PARAM; +} + +int dc_audio_muxer_close(AudioOutputFile *audio_output_file) +{ + switch (audio_output_file->muxer_type) { + case FFMPEG_AUDIO_MUXER: + return dc_ffmpeg_audio_muxer_close(audio_output_file); +#ifndef GPAC_DISABLE_ISOM + case GPAC_AUDIO_MUXER: + dc_gpac_audio_isom_close_seg(audio_output_file); + return dc_gpac_audio_isom_close(audio_output_file); + case GPAC_INIT_AUDIO_MUXER: + return dc_gpac_audio_isom_close_seg(audio_output_file); +#endif + default: + return GF_BAD_PARAM; + } + + return GF_BAD_PARAM; +} diff --git a/applications/dashcast/audio_muxer.h b/applications/dashcast/audio_muxer.h new file mode 100644 index 0000000..7c1d95e --- /dev/null +++ b/applications/dashcast/audio_muxer.h @@ -0,0 +1,131 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef AUDIO_MUXER_H_ +#define AUDIO_MUXER_H_ + +#include +#include "../../modules/ffmpeg_in/ffmpeg_in.h" +#include "libavutil/fifo.h" +#include "libavformat/avformat.h" +#include "libavdevice/avdevice.h" +#ifdef DC_AUDIO_RESAMPLER +#include "libavresample/avresample.h" +#endif +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" +#include +#include +#include +#include "audio_data.h" + + +typedef enum { + FFMPEG_AUDIO_MUXER, + GPAC_AUDIO_MUXER, + GPAC_INIT_AUDIO_MUXER +} AudioMuxerType; + +/* + * AudioOutputFile structure has the data needed + * to encode audio samples and write them on the file. + * It reads the data from a circular buffer so it needs + * to keep the index to that circular buffer. This index is + * available in Consumer data structure. + * + */ +typedef struct { + //AudioDataConf *audio_data_conf; + + /* File format context structure */ + AVFormatContext *av_fmt_ctx; + AVCodec *codec; + AVCodecContext *codec_ctx; + +#ifndef GPAC_DISABLE_ISOM + GF_ISOFile *isof; + GF_ISOSample *sample; +#endif + + int dts; + + /* The index to the audio stream in the file */ + int astream_idx; + + /* It keeps the index with which encoder access to the circular buffer (as a consumer) */ + Consumer consumer; + +#ifdef DC_AUDIO_RESAMPLER + /* Optional audio resampling between the decoder and the encoder */ + AVAudioResampleContext *aresampler; +#endif + + /* Variables that encoder needs to encode data */ + AVFrame *aframe; + uint8_t *adata_buf; + int frame_bytes; + AVPacket packet; + + /* + * Audio samples stored in the AVFrame are not always + * complete. Which means more than 1 AVFrame is needed + * to complete an access unit. This fifo is provided + * to store audio samples in the fifo and once an access unit + * is complete we can encode it. + */ + AVFifoBuffer *fifo; + + AudioMuxerType muxer_type; + + /* Accumulated sample */ + //int acc_samples; + + int frame_per_seg; + int frame_per_frag; + int first_dts; + + u32 seg_marker; +} AudioOutputFile; + +int dc_audio_muxer_init(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf, AudioMuxerType muxer_type, int frame_per_seg, int frame_per_frag, u32 seg_marker); +void dc_audio_muxer_free(AudioOutputFile *audio_output_file); + +/* + * Open the output audio + * + * @param audio_output_file [out] open the audio output on this file + * + * @param audio_data_conf [in] the structure containing the + * configuration of the output file (bitrate, samplerate, name, channels) + * + * @return 0 on success, -1 on failure + */ +GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, char *id_name, int seg); + +GF_Err dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb); + +GF_Err dc_audio_muxer_close(AudioOutputFile *audio_output_file); + +#endif /* AUDIO_MUXER_H_ */ diff --git a/applications/dashcast/circular_buffer.c b/applications/dashcast/circular_buffer.c new file mode 100644 index 0000000..4f1e6f4 --- /dev/null +++ b/applications/dashcast/circular_buffer.c @@ -0,0 +1,263 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "circular_buffer.h" + + +//#define DEBUG + + +void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode mode, int max_num_consumers) +{ + u32 i; + circular_buf->size = size; + circular_buf->list = gf_malloc(size * sizeof(Node)); + circular_buf->mode = mode; + circular_buf->max_num_consumers = max_num_consumers; + + for (i=0; ilist[i].num_producers = 0; + circular_buf->list[i].num_consumers = 0; + circular_buf->list[i].num_consumers_accessed = 0; + circular_buf->list[i].marked = 0; + circular_buf->list[i].num_consumers_waiting = 0; + circular_buf->list[i].consumers_semaphore = gf_sema_new(1000, 0); + circular_buf->list[i].producers_semaphore = gf_sema_new(1000, 0); + circular_buf->list[i].mutex = gf_mx_new("Circular Buffer Mutex"); + } +} + +void dc_circular_buffer_destroy(CircularBuffer *circular_buf) +{ + u32 i; + for (i = 0; i < circular_buf->size; i++) { + gf_sema_del(circular_buf->list[i].consumers_semaphore); + gf_sema_del(circular_buf->list[i].producers_semaphore); + gf_mx_del(circular_buf->list[i].mutex); + } + + gf_free(circular_buf->list); +} + +void dc_consumer_init(Consumer *consumer, int max_idx, char *name) +{ + consumer->idx = 0; + consumer->max_idx = max_idx; + strcpy(consumer->name, name); +} + +void * dc_consumer_consume(Consumer *consumer, CircularBuffer *circular_buf) +{ + return circular_buf->list[consumer->idx].data; +} + +int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf) +{ + Node *node = &circular_buf->list[consumer->idx]; + + gf_mx_p(node->mutex); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s enters lock %d\n", consumer->name, consumer->idx)); + if (node->marked == 2) { + gf_mx_v(node->mutex); + return -1; + } + + node->num_consumers_waiting++; + while (node->num_producers || !node->marked) { + gf_mx_v(node->mutex); + gf_sema_wait(node->consumers_semaphore); + gf_mx_p(node->mutex); + + if (node->marked == 2) { + gf_mx_v(node->mutex); + return -1; + } + } + node->num_consumers_waiting--; + + if (node->marked == 2) { + gf_mx_v(node->mutex); + return -1; + } + node->num_consumers++; + node->num_consumers_accessed++; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s exits lock %d \n", consumer->name, consumer->idx)); + gf_mx_v(node->mutex); + + return 0; +} + +int dc_consumer_unlock(Consumer *consumer, CircularBuffer *circular_buf) +{ + int last_consumer = 0; + Node *node = &circular_buf->list[consumer->idx]; + + gf_mx_p(node->mutex); + node->num_consumers--; + + if (node->num_consumers_accessed == circular_buf->max_num_consumers) { + node->marked = 0; + node->num_consumers_accessed = 0; + last_consumer = 1; + } + + gf_sema_notify(node->producers_semaphore, 1); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s unlock %d \n", consumer->name, consumer->idx)); + gf_mx_v(node->mutex); + + return last_consumer; +} + +int dc_consumer_unlock_previous(Consumer *consumer, CircularBuffer *circular_buf) +{ + int node_idx = (consumer->idx - 1 + consumer->max_idx) % consumer->max_idx; + int last_consumer = 0; + Node *node = &circular_buf->list[node_idx]; + + gf_mx_p(node->mutex); + + node->num_consumers--; + if (node->num_consumers < 0) + node->num_consumers = 0; + + if (node->num_consumers_accessed == circular_buf->max_num_consumers) { + if (node->marked != 2) + node->marked = 0; + node->num_consumers_accessed = 0; + last_consumer = 1; + } + + gf_sema_notify(node->producers_semaphore, 1); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s unlock %d \n", consumer->name, node_idx)); + gf_mx_v(node->mutex); + + return last_consumer; +} + +void dc_consumer_advance(Consumer *consumer) +{ + consumer->idx = (consumer->idx + 1) % consumer->max_idx; +} + +void dc_producer_init(Producer *producer, int max_idx, char *name) +{ + producer->idx = 0; + producer->max_idx = max_idx; + strcpy(producer->name, name); +} + +void * dc_producer_produce(Producer *producer, CircularBuffer *circular_buf) +{ + return circular_buf->list[producer->idx].data; +} + +int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf) +{ + Node *node = &circular_buf->list[producer->idx]; + + gf_mx_p(node->mutex); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s enters lock %d \n", producer->name, producer->idx)); + + if ( (circular_buf->mode == LIVE_CAMERA || circular_buf->mode == LIVE_MEDIA) && (node->num_consumers || node->marked)) { + gf_mx_v(node->mutex); + return -1; + } + + while (node->num_consumers || node->marked) { + gf_mx_v(node->mutex); + gf_sema_wait(node->producers_semaphore); + gf_mx_p(node->mutex); + } + + node->num_producers++; + if (circular_buf->size>1) { + node->marked = 1; + } + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s exits lock %d \n", producer->name, producer->idx)); + gf_mx_v(node->mutex); + + return 0; +} + +void dc_producer_unlock(Producer *producer, CircularBuffer *circular_buf) +{ + Node *node = &circular_buf->list[producer->idx]; + + gf_mx_p(node->mutex); + node->num_producers--; + gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s unlock %d \n", producer->name, producer->idx)); + gf_mx_v(node->mutex); +} + +void dc_producer_unlock_previous(Producer *producer, CircularBuffer *circular_buf) +{ + int node_idx = (producer->idx - 1 + producer->max_idx) % producer->max_idx; + Node *node = &circular_buf->list[node_idx]; + + gf_mx_p(node->mutex); + node->num_producers = 0; + gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s unlock %d \n", producer->name, node_idx)); + gf_mx_v(node->mutex); +} + +void dc_producer_advance(Producer *producer, CircularBuffer *circular_buf) +{ + if (circular_buf->size == 1) { + Node *node = &circular_buf->list[producer->idx]; + gf_mx_p(node->mutex); + node->marked = 1; + gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting); + gf_mx_v(node->mutex); + } + producer->idx = (producer->idx + 1) % producer->max_idx; +} + +void dc_producer_end_signal(Producer *producer, CircularBuffer *circular_buf) +{ + Node *node = &circular_buf->list[producer->idx]; + + gf_mx_p(node->mutex); + node->marked = 2; + gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s sends end signal %d \n", producer->name, producer->idx)); + gf_mx_v(node->mutex); +} + +void dc_producer_end_signal_previous(Producer *producer, CircularBuffer *circular_buf) +{ + int i_node = (producer->max_idx + producer->idx - 1) % producer->max_idx; + Node *node = &circular_buf->list[i_node]; + + gf_mx_p(node->mutex); + node->marked = 2; + gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s sends end signal %d \n", producer->name, node)); + gf_mx_v(node->mutex); +} diff --git a/applications/dashcast/circular_buffer.h b/applications/dashcast/circular_buffer.h new file mode 100644 index 0000000..e660440 --- /dev/null +++ b/applications/dashcast/circular_buffer.h @@ -0,0 +1,246 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef CIRCULAR_BUFFER_H_ +#define CIRCULAR_BUFFER_H_ + +#include +#include +#include + + +/* + * The method (mode) of multithread management. + * It can be LIVE or OFFLINE. + * LIVE means that the system is real time. The producer does not wait + * for anyone and it always produces and finds a place on the circular buffer. + * OFFLINE means that the system is working offline, so the producer can + * wait for the consumers to finish their job. + */ +typedef enum { + LIVE_CAMERA, + LIVE_MEDIA, + ON_DEMAND +} LockMode; + +/* + * Every node of the circular buffer has a data, plus + * all the variables needed for multithread management. + */ +typedef struct { + /* Pointer to the data on the node */ + void *data; + /* The number of the producer currently using this node */ + int num_producers; + /* The number of consumer currently using this node */ + int num_consumers; + /* The number of consumer currently waiting for this node */ + int num_consumers_waiting; + /* Mutex used for synchronizing the users of this node. */ + GF_Mutex *mutex; + /* Semaphore for producer */ + GF_Semaphore *producers_semaphore; + /* Semaphore for consumers */ + GF_Semaphore *consumers_semaphore; + /* If marked is 0 it means the data on this node is not valid. + * If marked is 1 it means that the data on this node is valid. + * If marked is 2 it means this node is the last node. */ + int marked; + /* Indicates the number of consumers which already accessed this node. + * It is used for the case where the last consumer has to do something. */ + int num_consumers_accessed; +} Node; + +/* + * The circular buffer has a size, a list of nodes and it + * has the number of consumers using it. Also it needs to know which + * locking mechanism it needs to use. (LIVE or OFFLINE) + */ +typedef struct { + /* The size of circular buffer */ + u32 size; + /* A list of all the nodes */ + Node *list; + /* The mode for multithread management. */ + LockMode mode; + /* The maximum number of the consumers using the circular buffer */ + u32 max_num_consumers; +} CircularBuffer; + +/* + * Producer has an index to the circular buffer. + */ +typedef struct { + /* The index where the producer is using */ + int idx; + /* The maximum of the index. (Which means the size of circular buffer) */ + int max_idx; + + char name[GF_MAX_PATH]; +} Producer; + +/* + * Consumer has an index to the circular buffer. + */ +typedef struct { + /* The index where the consumer is using */ + int idx; + /* The maximum of the index. (Which means the size of circular buffer) */ + int max_idx; + + char name[GF_MAX_PATH]; +} Consumer; + +/* + * Create a circular buffer + * + * @param circular_buf [out] circular buffer to be created + * @param size [in] size of circular buffer + * @param mode [in] mode of multithread management (LIVE or OFFLINE) + * @param num_consumers [in] maximum number of the consumers of the circular buffer + */ +void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode mode, int num_consumers); + +/* + * Destroy the circular buffer + * + * @param circular_buf [in] circular buffer to be destroyed + */ +void dc_circular_buffer_destroy(CircularBuffer *circular_buf); + +/* + * Initialize a consumer + * + * @param consumer [out] the consumer to be initialize + * @param num_consumers [in] maximum number of the consumers + */ +void dc_consumer_init(Consumer *consumer, int num_consumers, char *name); + +/* + * Return the data in the node in question. (circular_buf[consumer index]) + * + * @param consumer [in] consumer + * @param circular_buf [in] circular buffer + */ +void * dc_consumer_consume(Consumer *consumer, CircularBuffer *circular_buf); + +/* + * Consumer lock on circular buffer + * + * @param consumer [in] consumer + * @param circular_buf [in] circular buffer + * + * @return 0 on success, -1 if the node in question is the last node and not usable. + */ +int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf); + +/* + * Consumer unlock on circular buffer + * + * @param consumer [in] consumer + * @param circular_buf [in] circular buffer + * + * @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer. + */ +int dc_consumer_unlock(Consumer *consumer, CircularBuffer *circular_buf); + +/* + * Consumer unlock on previous node of the circular buffer + * + * @param consumer [in] consumer + * @param circular_buf [in] circular buffer + * + * @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer. + */ +int dc_consumer_unlock_previous(Consumer *consumer, CircularBuffer *circular_buf); + +/* + * Consumer leads its index + * + * @param consumer [in] consumer + */ +void dc_consumer_advance(Consumer *consumer); + +/* + * Initialize a producer + * + * @param producer [out] the producer to be initialize + * @param maxpro [in] maximum number of the producers + */ +void dc_producer_init(Producer *producer, int maxpro, char *name); + +/* + * Return the data in the node in question. (circular_buf[consumer index]) + * + * @param producer [in] producer + * @param circular_buf [in] circular buffer + */ +void * dc_producer_produce(Producer *producer, CircularBuffer *circular_buf); + +/* + * Producer lock on circular buffer + * + * @param producer [in] producer + * @param circular_buf [in] circular buffer + * + * @return 0 on success, -1 if the mode is live and cannot wait. + */ +int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf); + +/* + * Producer unlock on circular buffer + * + * @param producer [in] producer + * @param circular_buf [in] circular buffer + */ +void dc_producer_unlock(Producer *producer, CircularBuffer *circular_buf); + +/* + * Producer unlock on the previous node of the circular buffer + * + * @param producer [in] producer + * @param circular_buf [in] circular buffer + */ +void dc_producer_unlock_previous(Producer *, CircularBuffer *); + +/* + * Producer leads its index + * + * @param producer [in] producer + * @param circular_buf [in] circular buffer + */ +void dc_producer_advance(Producer *producer, CircularBuffer *); + +/* + * Producer signal that the current node is the last node + * + * @param producer [in] producer + * @param circular_buf [in] circular buffer + */ +void dc_producer_end_signal(Producer *producer, CircularBuffer *circular_buf); + +void dc_producer_end_signal_previous(Producer *producer, CircularBuffer *circular_buf); + +#endif /* CIRCULAR_BUFFER_H_ */ diff --git a/applications/dashcast/cmd_data.c b/applications/dashcast/cmd_data.c new file mode 100644 index 0000000..176369f --- /dev/null +++ b/applications/dashcast/cmd_data.c @@ -0,0 +1,920 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "cmd_data.h" + + +#define DASHCAST_CHECK_NEXT_ARG \ + i++; \ + if (i >= argc) { \ + fprintf(stderr, "%s: %s", command_error, argv[i]); \ + fprintf(stderr, "%s", command_usage); \ + return -1; \ + } + + +int dc_str_to_resolution(char *str, int *width, int *height) +{ + char *token = strtok(str, "x"); + if (!token) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot parse resolution string.\n")); + return -1; + } + *width = atoi(token); + + token = strtok(NULL, " "); + if (!token) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot parse resolution string.\n")); + return -1; + } + *height = atoi(token); + + return 0; +} + + +#define DEFAULT_VIDEO_BITRATE 1000000 +#define DEFAULT_VIDEO_FRAMERATE 25 +#define DEFAULT_VIDEO_WIDTH 640 +#define DEFAULT_VIDEO_HEIGHT 480 +#define DEFAULT_VIDEO_CODEC "libx264" +#define DEFAULT_AUDIO_BITRATE 192000 +#define DEFAULT_AUDIO_SAMPLERATE 44100 +#define DEFAULT_AUDIO_CHANNELS 2 +#define DEFAULT_AUDIO_CODEC "aac" + + +static void dc_create_configuration(CmdData *cmd_data) +{ + u32 i; + GF_Config *conf = cmd_data->conf; + u32 sec_count = gf_cfg_get_section_count(conf); + if (!sec_count) { + gf_cfg_set_key(conf, "v1", "type", "video"); + gf_cfg_set_key(conf, "a1", "type", "audio"); + sec_count = gf_cfg_get_section_count(conf); + } + for (i=0; ivideo_data_conf.bitrate == -1) + cmd_data->video_data_conf.bitrate = DEFAULT_VIDEO_BITRATE; + snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.bitrate); + gf_cfg_set_key(conf, section_name, "bitrate", value); + } + + if (!gf_cfg_get_key(conf, section_name, "framerate")) { + if (cmd_data->video_data_conf.framerate == -1) + cmd_data->video_data_conf.framerate = DEFAULT_VIDEO_FRAMERATE; + snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.framerate); + gf_cfg_set_key(conf, section_name, "framerate", value); + } + + if (!gf_cfg_get_key(conf, section_name, "width")) { + if (cmd_data->video_data_conf.width == -1) + cmd_data->video_data_conf.width = DEFAULT_VIDEO_WIDTH; + snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.width); + gf_cfg_set_key(conf, section_name, "width", value); + } + + if (!gf_cfg_get_key(conf, section_name, "height")) { + if (cmd_data->video_data_conf.height == -1) + cmd_data->video_data_conf.height = DEFAULT_VIDEO_HEIGHT; + snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.height); + gf_cfg_set_key(conf, section_name, "height", value); + } + + if (!gf_cfg_get_key(conf, section_name, "crop_x")) { + if (cmd_data->video_data_conf.crop_x == -1) + cmd_data->video_data_conf.crop_x = 0; + snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.crop_x); + gf_cfg_set_key(conf, section_name, "crop_x", value); + } + if (!gf_cfg_get_key(conf, section_name, "low_delay")) { + gf_cfg_set_key(conf, section_name, "low_delay", cmd_data->video_data_conf.low_delay ? "yes" : "no"); + } + + if (!gf_cfg_get_key(conf, section_name, "crop_y")) { + if (cmd_data->video_data_conf.crop_y == -1) + cmd_data->video_data_conf.crop_y = 0; + snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.crop_y); + gf_cfg_set_key(conf, section_name, "crop_y", value); + } + + if (!gf_cfg_get_key(conf, section_name, "codec")) + gf_cfg_set_key(conf, section_name, "codec", DEFAULT_VIDEO_CODEC); + } + + if (strcmp(section_type, "audio") == 0) { + if (!gf_cfg_get_key(conf, section_name, "bitrate")) { + if (cmd_data->audio_data_conf.bitrate == -1) + cmd_data->audio_data_conf.bitrate = DEFAULT_AUDIO_BITRATE; + snprintf(value, sizeof(value), "%d", cmd_data->audio_data_conf.bitrate); + gf_cfg_set_key(conf, section_name, "bitrate", value); + } + + if (!gf_cfg_get_key(conf, section_name, "samplerate")) { + if (cmd_data->audio_data_conf.samplerate == -1) + cmd_data->audio_data_conf.samplerate = DEFAULT_AUDIO_SAMPLERATE; + snprintf(value, sizeof(value), "%d", cmd_data->audio_data_conf.samplerate); + gf_cfg_set_key(conf, section_name, "samplerate", value); + } + + if (!gf_cfg_get_key(conf, section_name, "channels")) { + if (cmd_data->audio_data_conf.channels == -1) + cmd_data->audio_data_conf.channels = DEFAULT_AUDIO_CHANNELS; + snprintf(value, sizeof(value), "%d", cmd_data->audio_data_conf.channels); + gf_cfg_set_key(conf, section_name, "channels", value); + } + + if (!gf_cfg_get_key(conf, section_name, "codec")) + gf_cfg_set_key(conf, section_name, "codec", DEFAULT_AUDIO_CODEC); + } + } +} + +int dc_read_configuration(CmdData *cmd_data) +{ + const char *opt; + u32 i; + GF_Config *conf = cmd_data->conf; + + u32 sec_count = gf_cfg_get_section_count(conf); + for (i=0; ifilename, section_name); + opt = gf_cfg_get_key(conf, section_name, "codec"); + if (!opt) opt = DEFAULT_VIDEO_CODEC; + strcpy(video_data_conf->codec, opt); + opt = gf_cfg_get_key(conf, section_name, "bitrate"); + video_data_conf->bitrate = opt ? atoi(opt) : DEFAULT_VIDEO_BITRATE; + opt = gf_cfg_get_key(conf, section_name, "framerate"); + video_data_conf->framerate = opt ? atoi(opt) : DEFAULT_VIDEO_FRAMERATE; + opt = gf_cfg_get_key(conf, section_name, "height"); + video_data_conf->height = opt ? atoi(opt) : DEFAULT_VIDEO_HEIGHT; + opt = gf_cfg_get_key(conf, section_name, "width"); + video_data_conf->width = opt ? atoi(opt) : DEFAULT_VIDEO_WIDTH; + opt = gf_cfg_get_key(conf, section_name, "crop_x"); + video_data_conf->crop_x = opt ? atoi(opt) : 0; + opt = gf_cfg_get_key(conf, section_name, "crop_y"); + video_data_conf->crop_x = opt ? atoi(opt) : 0; + opt = gf_cfg_get_key(conf, section_name, "low_delay"); + video_data_conf->low_delay = (opt && !strcmp(opt, "yes")) ? 1 : 0; + opt = gf_cfg_get_key(conf, section_name, "custom"); + if (opt) { + if (strlen(opt) >= GF_MAX_PATH) + fprintf(stderr, "Warning: video custom opt is too long. Truncating.\n"); + strncpy(video_data_conf->custom, opt, GF_MAX_PATH-1); + } + gf_list_add(cmd_data->video_lst, (void *) video_data_conf); + } + else if (strcmp(section_type, "audio") == 0) + { + AudioDataConf *audio_data_conf; + GF_SAFEALLOC(audio_data_conf, AudioDataConf); + strcpy(audio_data_conf->filename, section_name); + opt = gf_cfg_get_key(conf, section_name, "codec"); + if (!opt) opt = DEFAULT_AUDIO_CODEC; + strcpy(audio_data_conf->codec, opt); + opt = gf_cfg_get_key(conf, section_name, "bitrate"); + audio_data_conf->bitrate = opt ? atoi(opt) : DEFAULT_AUDIO_BITRATE; + opt = gf_cfg_get_key(conf, section_name, "samplerate"); + audio_data_conf->samplerate = opt ? atoi(opt) : DEFAULT_AUDIO_SAMPLERATE; + opt = gf_cfg_get_key(conf, section_name, "channels"); + audio_data_conf->channels = opt ? atoi(opt) : DEFAULT_AUDIO_CHANNELS; + opt = gf_cfg_get_key(conf, section_name, "custom"); + if (opt) { + if (strlen(opt) >= GF_MAX_PATH) + fprintf(stderr, "Warning: audio custom opt is too long. Truncating.\n"); + strncpy(audio_data_conf->custom, opt, GF_MAX_PATH-1); + } + gf_list_add(cmd_data->audio_lst, (void *) audio_data_conf); + } else { + fprintf(stderr, "Configuration file: type %s is not supported.\n", section_type); + } + } + + fprintf(stdout, "\33[34m\33[1m"); + fprintf(stdout, "Configurations:\n"); + for (i=0; ivideo_lst); i++) { + VideoDataConf *video_data_conf = gf_list_get(cmd_data->video_lst, i); + fprintf(stdout, " id:%s\tres:%dx%d\tvbr:%d\n", video_data_conf->filename, + video_data_conf->width, video_data_conf->height, + video_data_conf->bitrate/*, video_data_conf->framerate, video_data_conf->codec*/); + } + + for (i=0; iaudio_lst); i++) { + AudioDataConf *audio_data_conf = gf_list_get(cmd_data->audio_lst, i); + fprintf(stdout, " id:%s\tabr:%d\n", audio_data_conf->filename, audio_data_conf->bitrate/*, audio_data_conf->samplerate, audio_data_conf->channels,audio_data_conf->codec*/); + } + fprintf(stdout, "\33[0m"); + fflush(stdout); + + return 0; +} + +/** + * Parse time from a string to a struct tm. + */ +static Bool parse_time(const char* str_time, struct tm *tm_time) +{ + if (!tm_time) + return GF_FALSE; + +#if defined(__GNUC__) + strptime(str_time, "%Y-%m-%d %H:%M:%S", tm_time); +#elif defined(WIN32) + assert(0); //TODO +#else +#error +#endif + + return GF_TRUE; +} + +int dc_read_switch_config(CmdData *cmd_data) +{ + u32 i; + int src_number; + char start_time[4096], end_time[4096]; + + time_t now_t = time(NULL); + struct tm start_tm = *localtime(&now_t); + struct tm end_tm = *localtime(&now_t); + + GF_Config *conf = cmd_data->switch_conf; + u32 sec_count = gf_cfg_get_section_count(conf); + + dc_task_init(&cmd_data->task_list); + + if (sec_count == 0) { + return 0; + } + + for (i = 0; i < sec_count; i++) { + const char *section_name = gf_cfg_get_section_name(conf, i); + const char *section_type = gf_cfg_get_key(conf, section_name, "type"); + + if (strcmp(section_type, "video") == 0) { + VideoDataConf *video_data_conf = gf_malloc(sizeof(VideoDataConf)); + + strcpy(video_data_conf->source_id, section_name); + strcpy(video_data_conf->filename, gf_cfg_get_key(conf, section_name, "source")); + + strcpy(start_time, gf_cfg_get_key(conf, section_name, "start")); + parse_time(start_time, &start_tm); + video_data_conf->start_time = mktime(&start_tm); + strcpy(end_time, gf_cfg_get_key(conf, section_name, "end")); + parse_time(end_time, &end_tm); + video_data_conf->end_time = mktime(&end_tm); + + gf_list_add(cmd_data->vsrc, (void *) video_data_conf); + + src_number = gf_list_count(cmd_data->vsrc); + + dc_task_add(&cmd_data->task_list, src_number, video_data_conf->source_id, video_data_conf->start_time, video_data_conf->end_time); + } + else if (strcmp(section_type, "audio") == 0) + { + AudioDataConf *audio_data_conf = gf_malloc(sizeof(AudioDataConf)); + strcpy(audio_data_conf->source_id, section_name); + strcpy(audio_data_conf->filename, gf_cfg_get_key(conf, section_name, "source")); + + strcpy(start_time, gf_cfg_get_key(conf, section_name, "start")); + parse_time(start_time, &start_tm); + audio_data_conf->start_time = mktime(&start_tm); + + strcpy(end_time, gf_cfg_get_key(conf, section_name, "end")); + parse_time(end_time, &end_tm); + audio_data_conf->end_time = mktime(&end_tm); + + gf_list_add(cmd_data->asrc, (void *) audio_data_conf); + } else { + fprintf(stdout, "Switch source configuration file: type %s is not supported.\n", section_type); + } + } + + fprintf(stdout, "\33[34m\33[1m"); + fprintf(stdout, "Sources:\n"); + for (i=0; ivsrc); i++) { + VideoDataConf *video_data_conf = gf_list_get(cmd_data->vsrc, i); + strftime(start_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&video_data_conf->start_time)); + strftime(end_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&video_data_conf->end_time)); + fprintf(stdout, " id:%s\tsource:%s\tstart:%s\tend:%s\n", video_data_conf->source_id, video_data_conf->filename, start_time, end_time); + } + + for (i=0; iasrc); i++) { + AudioDataConf *audio_data_conf = gf_list_get(cmd_data->asrc, i); + strftime(start_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&audio_data_conf->start_time)); + strftime(end_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&audio_data_conf->end_time)); + fprintf(stdout, " id:%s\tsource:%s\tstart:%s\tend:%s\n", audio_data_conf->source_id, audio_data_conf->filename, start_time, end_time); + } + fprintf(stdout, "\33[0m"); + fflush(stdout); + + return 0; +} + +void dc_cmd_data_init(CmdData *cmd_data) +{ + memset(cmd_data, 0, sizeof(CmdData)); + dc_audio_data_set_default(&cmd_data->audio_data_conf); + dc_video_data_set_default(&cmd_data->video_data_conf); + + cmd_data->mode = ON_DEMAND; + cmd_data->ast_offset = -1; + cmd_data->min_buffer_time = -1; + cmd_data->minimum_update_period = -1; + cmd_data->use_source_timing = 1; + + cmd_data->audio_lst = gf_list_new(); + cmd_data->video_lst = gf_list_new(); + cmd_data->asrc = gf_list_new(); + cmd_data->vsrc = gf_list_new(); +} + +void dc_cmd_data_destroy(CmdData *cmd_data) +{ + while (gf_list_count(cmd_data->audio_lst)) { + AudioDataConf *audio_data_conf = gf_list_last(cmd_data->audio_lst); + gf_list_rem_last(cmd_data->audio_lst); + gf_free(audio_data_conf); + } + gf_list_del(cmd_data->audio_lst); + + while (gf_list_count(cmd_data->video_lst)) { + VideoDataConf *video_data_conf = gf_list_last(cmd_data->video_lst); + gf_list_rem_last(cmd_data->video_lst); + gf_free(video_data_conf); + } + gf_list_del(cmd_data->video_lst); + + gf_list_del(cmd_data->asrc); + gf_list_del(cmd_data->vsrc); + gf_cfg_del(cmd_data->conf); + gf_cfg_del(cmd_data->switch_conf); + if (cmd_data->logfile) + gf_fclose(cmd_data->logfile); + + dc_task_destroy(&cmd_data->task_list); + + gf_sys_close(); +} + +static void on_dc_log(void *cbk, u32 ll, u32 lm, const char *av_fmt_ctx, va_list list) +{ + FILE *logs = cbk; + vfprintf(logs, av_fmt_ctx, list); + fflush(logs); +} + +int dc_parse_command(int argc, char **argv, CmdData *cmd_data) +{ + Bool use_mem_track = GF_FALSE; + int i; + + const char *command_usage = + "Usage: DashCast [options]\n" + "GPAC version " GPAC_FULL_VERSION"\n" + "\n" + "General options:\n" + " -log-file filename set output log file. Also works with -lf\n" + " -logs LOGS set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" +#ifdef GPAC_MEMORY_TRACKING + " -mem-track enable the memory tracker\n" +#endif + " -conf filename set the configuration file name (default: dashcast.conf)\n" + " -switch-source filename set the configuration file name for source switching\n" + "\n" + "Live options:\n" + " -live system is live and input is a camera\n" + " -live-media system is live and input is a media file\n" + " -no-loop system does not loop on the input media file when live\n" + " -dynamic-ast changes segment availability start time at each MPD generation (old behaviour but not allowed in most profiles)\n" + " -insert-utc inserts UTC clock at the start of each segment\n" + "\n" + "Source options:\n" + " -npts use frame counting for timestamps (not error-free) instead of source timing (default)\n" + " -av string set the source name for a multiplexed audio and video input\n" + " - if this option is present, neither '-a' nor '-v' shall be present\n" + "* Video options:\n" + " -v string set the source name for a video input\n" + " - if input is from a webcam, use \"/dev/video[x]\" \n" + " where x is the video device number\n" + " - if input is the screen video, use \":0.0+[x],[y]\" \n" + " which captures from upper-left at x,y\n" + " - if input is from stdin, use \"pipe:\"\n" + " -vf string set the input video format\n" +#ifdef WIN32 + " - to capture from a VfW webcam, set vfwcap\n" + " - to capture from a directshow device, set dshow\n" +#else + " - to capture from a webcam, set video4linux2\n" + " - to capture the screen, set x11grab\n" + " -v4l2f inv4l2f inv4l2f is the input format for webcam acquisition\n" + " - it can be mjpeg, yuyv422, etc.\n" +#endif + " -pixf FMT set the input pixel format\n" + " -vfr N force the input video framerate\n" + " -vres WxH force the video resolution (e.g. 640x480)\n" + " -vcrop XxY crop the source video from X pixels left and Y pixels top. Must be used with -vres.\n" + "* Audio options:\n" + " -a string set the source name for an audio input\n" + " - if input is from microphone, use \"plughw:[x],[y]\"\n" + " where x is the card number and y is the device number\n" + " -af string set the input audio format\n" + "\n" + "Output options:\n" + "* Video encoding options:\n" + " -vcodec string set the output video codec (default: h264)\n" +#if 0 //TODO: bind to option and params - test first how it binds to current input parameters + " -vb int set the output video bitrate (in bits)\n" +#endif + " -vcustom string send custom parameters directly to the video encoder\n" + " -gdr use Gradual Decoder Refresh feature for video encoding (h264 codec only)\n" + " -gop specify GOP size in frames - default is framerate (1 sec gop)\n" + " -low-delay specify that low delay settings should be used (no B-frames, fast encoding)\n" + "* Audio encoding options:\n" + " -acodec string set the output audio codec (default: aac)\n" +#if 0 //TODO: bind to option and params - test first how it binds to current input parameters + " -ab int set the output audio bitrate in bits (default: 192000)\n" + " -as int set the sample rate (default: 44100)\n" + " -ach int set the number of output audio channels (default: 2)\n" +#endif + " -acustom string send custom parameters directly to the audio encoder\n" + "\n" + "DASH options:\n" + " -seg-dur dur:int set the segment duration in millisecond (default value: 1000)\n" + " -frag dur:int set the fragment duration in millisecond (default value: 1000) (same as -frag-dur)\n" + " -seg-marker marker:4cc add a marker box named marker at the end of DASH segment\n" + " -out outdir:str outdir is the output data directory (default: output)\n" + " -mpd mpdname:str mpdname is the MPD file name (default: dashcast.mpd)\n" + " -ast-offset dur:int dur is the MPD availabilityStartTime shift in milliseconds (default value: 0)\n" + " -mpd-refresh dur:int dur is the MPD minimumUpdatePeriod in seconds\n" + " -time-shift dur:int dur is the MPD TimeShiftBufferDepth in seconds\n" + " - the default value is 10. Specify -1 to keep all files.\n" + " -min-buffer dur:float dur is the MPD minBufferTime in seconds (default value: 1.0)\n" + " -base-url baseurl:str baseurl is the MPD BaseURL\n" + "\n" + "\n" + "Examples:\n" + "\n" + " DashCast -av test.avi -live-media\n" + " DashCast -a test_audio.mp3 -v test_audio.mp4 -live-media\n" +#ifdef WIN32 + " DashCast -vf vfwcap -vres 1280x720 -vfr 24 -v 0 -live\n" + " DashCast -vf dshow -vres 1280x720 -vfr 24 -v video=\"screen-capture-recorder\" -live (please install http://screencapturer.sf.net/)\n" + " DashCast -vf dshow -vres 1280x720 -vfr 24 -v video=\"YOUR-WEBCAM\" -pixf yuv420p -live\n" +#elif defined(__DARWIN) || defined(__APPLE__) + " DashCast -vf avfoundation -vres 1280x720 -v \"FaceTime HD Camera\" -vfr 25 -live\n" + " DashCast -vf avfoundation -vres 1280x720 -v \"Capture screen 0\" -vfr 25 -live\n" +#else + " DashCast -vf video4linux2 -vres 1280x720 -vfr 24 -v4l2f mjpeg -v /dev/video0 -af alsa -a plughw:1,0 -live\n" + " DashCast -vf x11grab -vres 800x600 -vfr 25 -v :0.0 -live\n" +#endif + "\n"; + + const char *command_error = "\33[31mUnknown option or missing mandatory argument.\33[0m\n"; + + if (argc == 1) { + fprintf(stderr, "%s", command_usage); + return -2; + } + +#ifdef GPAC_MEMORY_TRACKING + i = 1; + while (i < argc) { + if (strcmp(argv[i], "-mem-track") == 0) { + use_mem_track = GF_TRUE; + break; + } + i++; + } +#endif + + gf_sys_init(use_mem_track); + + gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); + if (use_mem_track) { + gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); + } + + /* Initialize command data */ + dc_cmd_data_init(cmd_data); + cmd_data->use_mem_track = use_mem_track; + + i = 1; + while (i < argc) { + if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-av") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strcmp(argv[i - 1], "-a") == 0 || strcmp(argv[i - 1], "-av") == 0) { + if (strcmp(cmd_data->audio_data_conf.filename, "") != 0) { + fprintf(stderr, "Audio source has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strcpy(cmd_data->audio_data_conf.filename, argv[i]); + } + + if (strcmp(argv[i - 1], "-v") == 0 || strcmp(argv[i - 1], "-av") == 0) { + if (strcmp(cmd_data->video_data_conf.filename, "") != 0) { + fprintf(stderr, "Video source has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strcpy(cmd_data->video_data_conf.filename, argv[i]); + } + + i++; + } else if (strcmp(argv[i], "-af") == 0 || strcmp(argv[i], "-vf") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strcmp(argv[i - 1], "-af") == 0) { + if (strcmp(cmd_data->audio_data_conf.format, "") != 0) { + fprintf(stderr, "Audio format has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strcpy(cmd_data->audio_data_conf.format, argv[i]); + } + if (strcmp(argv[i - 1], "-vf") == 0) { + if (strcmp(cmd_data->video_data_conf.format, "") != 0) { + fprintf(stderr, "Video format has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strcpy(cmd_data->video_data_conf.format, argv[i]); + } + i++; + } else if (strcmp(argv[i], "-pixf") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strcmp(cmd_data->video_data_conf.pixel_format, "") != 0) { + fprintf(stderr, "Input pixel format has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strcpy(cmd_data->video_data_conf.pixel_format, argv[i]); + i++; + } else if (strcmp(argv[i], "-vfr") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->video_data_conf.framerate != -1) { + fprintf(stderr, "Video framerate has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->video_data_conf.framerate = atoi(argv[i]); + i++; + } else if (strcmp(argv[i], "-vres") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->video_data_conf.height != -1 && cmd_data->video_data_conf.width != -1) { + fprintf(stderr, "Video resolution has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + dc_str_to_resolution(argv[i], &cmd_data->video_data_conf.width, &cmd_data->video_data_conf.height); + i++; + } else if (strcmp(argv[i], "-vcrop") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->video_data_conf.crop_x && cmd_data->video_data_conf.crop_y) { + fprintf(stderr, "Video crop has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + dc_str_to_resolution(argv[i], &cmd_data->video_data_conf.crop_x, &cmd_data->video_data_conf.crop_y); + i++; + } else if (strcmp(argv[i], "-vcodec") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strcmp(cmd_data->video_data_conf.codec, "") != 0) { + fprintf(stderr, "Video codec has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strncpy(cmd_data->video_data_conf.codec, argv[i], GF_MAX_PATH-1); + i++; + } else if (strcmp(argv[i], "-vcustom") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strlen(cmd_data->video_data_conf.custom)) { + fprintf(stderr, "Video custom has already been specified: appending\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + if (strlen(argv[i]) >= GF_MAX_PATH) + fprintf(stderr, "Warning: video custom is too long. Truncating.\n"); + strncpy(cmd_data->video_data_conf.custom, argv[i], GF_MAX_PATH-1); + i++; + } else if (strcmp(argv[i], "-acodec") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strcmp(cmd_data->audio_data_conf.codec, "") != 0) { + fprintf(stderr, "Audio codec has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strncpy(cmd_data->audio_data_conf.codec, argv[i], GF_MAX_PATH-1); + i++; + } else if (strcmp(argv[i], "-acustom") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strlen(cmd_data->audio_data_conf.custom)) { + fprintf(stderr, "Audio custom has already been specified: appending\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + if (strlen(argv[i]) >= GF_MAX_PATH) + fprintf(stderr, "Warning: audio custom is too long. Truncating.\n"); + strncpy(cmd_data->audio_data_conf.custom, argv[i], GF_MAX_PATH-1); + i++; + } else if (strcmp(argv[i], "-conf") == 0) { + DASHCAST_CHECK_NEXT_ARG + cmd_data->conf = gf_cfg_force_new(NULL, argv[i]); + i++; + } else if (strcmp(argv[i], "-switch-source") == 0) { + DASHCAST_CHECK_NEXT_ARG + cmd_data->switch_conf = gf_cfg_force_new(NULL, argv[i]); + i++; + } else if (strcmp(argv[i], "-out") == 0) { + DASHCAST_CHECK_NEXT_ARG + strcpy(cmd_data->out_dir, argv[i]); + i++; +#ifndef WIN32 + } else if (strcmp(argv[i], "-v4l2f") == 0) { + DASHCAST_CHECK_NEXT_ARG + strcpy(cmd_data->video_data_conf.v4l2f, argv[i]); + i++; +#endif + } else if (strcmp(argv[i], "-seg-marker") == 0) { + char *m; + DASHCAST_CHECK_NEXT_ARG + m = argv[i]; + if (strlen(m) == 4) { + cmd_data->seg_marker = GF_4CC(m[0], m[1], m[2], m[3]); + } else { + fprintf(stderr, "Invalid marker box name specified: %s\n", m); + return -1; + } + i++; + } else if (strcmp(argv[i], "-mpd") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strcmp(cmd_data->mpd_filename, "") != 0) { + fprintf(stderr, "MPD file has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strncpy(cmd_data->mpd_filename, argv[i], GF_MAX_PATH-1); + i++; + } else if (strcmp(argv[i], "-seg-dur") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->seg_dur != 0) { + fprintf(stderr, "Segment duration has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->seg_dur = atoi(argv[i]); + i++; + } else if ((strcmp(argv[i], "-frag-dur") == 0) || (strcmp(argv[i], "-frag") == 0)) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->frag_dur != 0) { + fprintf(stderr, "Fragment duration has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->frag_dur = atoi(argv[i]); + i++; + } else if (strcmp(argv[i], "-ast-offset") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->ast_offset != -1) { + fprintf(stderr, "AvailabilityStartTime offset has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->ast_offset = atoi(argv[i]); + i++; + } else if (strcmp(argv[i], "-mpd-refresh") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->minimum_update_period != -1) { + fprintf(stderr, "minimumUpdatePeriod (mpd-refresh) has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->minimum_update_period = atoi(argv[i]); + i++; + } else if (strcmp(argv[i], "-time-shift") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->time_shift != 0) { + fprintf(stderr, "TimeShiftBufferDepth has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->time_shift = atoi(argv[i]); + i++; + } else if (strcmp(argv[i], "-gop") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->gop_size != 0) { + fprintf(stderr, "GOP size has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->gop_size = atoi(argv[i]); + i++; + } else if (strcmp(argv[i], "-min-buffer") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (cmd_data->min_buffer_time != -1) { + fprintf(stderr, "Min Buffer Time has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + cmd_data->min_buffer_time = (float)atof(argv[i]); + i++; + } else if (strcmp(argv[i], "-base-url") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (strcmp(cmd_data->base_url, "") != 0) { + fprintf(stderr, "BaseURL has already been specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + strncpy(cmd_data->base_url, argv[i], GF_MAX_PATH-1); + i++; + } else if (strcmp(argv[i], "-low-delay") == 0) { + cmd_data->video_data_conf.low_delay = 1; + i++; + } else if (strcmp(argv[i], "-live") == 0) { + cmd_data->mode = LIVE_CAMERA; + i++; + } else if (strcmp(argv[i], "-npts") == 0) { + cmd_data->use_source_timing = 0; + i++; + } else if (strcmp(argv[i], "-live-media") == 0) { + cmd_data->mode = LIVE_MEDIA; + i++; + } else if (strcmp(argv[i], "-no-loop") == 0) { + cmd_data->no_loop = 1; + i++; + } else if (strcmp(argv[i], "-insert-utc") == 0) { + cmd_data->insert_utc = 1; + i++; + } else if (strcmp(argv[i], "-dynamic-ast") == 0) { + cmd_data->use_dynamic_ast = 1; + i++; + } else if (strcmp(argv[i], "-send-message") == 0) { + //FIXME: unreferenced option. Seems related to a separate fragment thread. + cmd_data->send_message = 1; + i++; + } else if (strcmp(argv[i], "-logs") == 0) { + DASHCAST_CHECK_NEXT_ARG + if (gf_log_set_tools_levels(argv[i]) != GF_OK) { + fprintf(stderr, "Invalid log format %s", argv[i]); + return 1; + } + i++; + } else if (strcmp(argv[i], "-mem-track") == 0) { + i++; +#ifndef GPAC_MEMORY_TRACKING + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n")); +#endif + } else if (!strcmp(argv[i], "-lf") || !strcmp(argv[i], "-log-file")) { + DASHCAST_CHECK_NEXT_ARG + cmd_data->logfile = gf_fopen(argv[i], "wt"); + gf_log_set_callback(cmd_data->logfile, on_dc_log); + i++; + } else if (strcmp(argv[i], "-gdr") == 0) { + if ( (i+1 <= argc) && (argv[i+1][0] != '-')) { + DASHCAST_CHECK_NEXT_ARG + cmd_data->gdr = atoi(argv[i]); + } else { + //for historical reasons in dashcast + cmd_data->gdr = 8; + } + i++; + } else { + fprintf(stderr, "%s: %s", command_error, argv[i]); + fprintf(stderr, "%s", command_usage); + return -1; + } + } + + if (strcmp(cmd_data->mpd_filename, "") == 0) { + strcpy(cmd_data->mpd_filename, "dashcast.mpd"); + } + + if (strcmp(cmd_data->out_dir, "") == 0) { + struct stat status; + strcpy(cmd_data->out_dir, "output"); + if (stat(cmd_data->out_dir, &status) != 0) { + gf_mkdir(cmd_data->out_dir); + } + } + + if (strcmp(cmd_data->video_data_conf.filename, "") == 0 && strcmp(cmd_data->audio_data_conf.filename, "") == 0) { + fprintf(stderr, "Audio/Video source must be specified.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + + if (cmd_data->seg_dur == 0) { + cmd_data->seg_dur = 1000; + } + + if (cmd_data->frag_dur == 0) { + cmd_data->frag_dur = cmd_data->seg_dur; + } + + if (cmd_data->ast_offset == -1) { + //generate MPD as soon as possible (no offset) + cmd_data->ast_offset = 0; + } + + if (cmd_data->mode == ON_DEMAND) + cmd_data->time_shift = -1; + else { + if (cmd_data->time_shift == 0) { + cmd_data->time_shift = 10; + } + } + + if (cmd_data->min_buffer_time == -1) { + cmd_data->min_buffer_time = 1.0; + } + + if ((cmd_data->minimum_update_period == -1) && (cmd_data->mode == LIVE_CAMERA)) { + fprintf(stderr, "MPD refresh time not set in live - defaulting to segment duration\n"); + cmd_data->minimum_update_period = cmd_data->seg_dur; + } + + //safety checks + if (cmd_data->video_data_conf.crop_x || cmd_data->video_data_conf.crop_y) { + if (cmd_data->video_data_conf.width == -1 && cmd_data->video_data_conf.height == -1) { + fprintf(stderr, "You cannot use '-vcrop' without '-vres'. Please check usage.\n"); + fprintf(stderr, "%s", command_usage); + return -1; + } + } + + fprintf(stdout, "\33[34m\33[1m"); + fprintf(stdout, "Options:\n"); + fprintf(stdout, " video source: %s\n", cmd_data->video_data_conf.filename); + if (strcmp(cmd_data->video_data_conf.format, "") != 0) { + fprintf(stdout, " video format: %s\n", cmd_data->video_data_conf.format); + } +#ifndef WIN32 + if (strcmp(cmd_data->video_data_conf.v4l2f, "") != 0) { + fprintf(stdout, " v4l2 format: %s\n", cmd_data->video_data_conf.v4l2f); + } +#endif + if (cmd_data->video_data_conf.framerate != -1) { + fprintf(stdout, " video framerate: %d\n", cmd_data->video_data_conf.framerate); + } + if (cmd_data->video_data_conf.height != -1 && cmd_data->video_data_conf.width != -1) { + fprintf(stdout, " video resolution: %dx%d\n", cmd_data->video_data_conf.width, cmd_data->video_data_conf.height); + } + if (cmd_data->video_data_conf.crop_x != -1 && cmd_data->video_data_conf.crop_y != -1) { + fprintf(stdout, " video crop: %dx%d\n", cmd_data->video_data_conf.crop_x, cmd_data->video_data_conf.crop_y); + } + + fprintf(stdout, " audio source: %s\n", cmd_data->audio_data_conf.filename); + if (strcmp(cmd_data->audio_data_conf.format, "") != 0) { + fprintf(stdout, " audio format: %s\n", cmd_data->audio_data_conf.format); + } + fprintf(stdout, "\33[0m"); + fflush(stdout); + + if (!cmd_data->conf) { + cmd_data->conf = gf_cfg_force_new(NULL, "dashcast.conf"); + dc_create_configuration(cmd_data); + } + dc_read_configuration(cmd_data); + + if (!cmd_data->switch_conf) { + cmd_data->switch_conf = gf_cfg_force_new(NULL, "switch.conf"); + } + dc_read_switch_config(cmd_data); + + return 0; +} diff --git a/applications/dashcast/cmd_data.h b/applications/dashcast/cmd_data.h new file mode 100644 index 0000000..73bdbf4 --- /dev/null +++ b/applications/dashcast/cmd_data.h @@ -0,0 +1,137 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef CMD_DATA_H_ +#define CMD_DATA_H_ + +#define MAX_SOURCE_NUMBER 20 + + +#include +#include +#include +#include +#include +#include +#include +#include "audio_data.h" +#include "video_data.h" +#include "task.h" + + +/* + * This structure corresponds to + * the data in command line + */ +typedef struct { + /* input video */ + VideoDataConf video_data_conf; + /* audio input data */ + AudioDataConf audio_data_conf; + /* Configuration file */ + GF_Config *conf; + /* Switch source configuration file */ + GF_Config *switch_conf; + /* MPD file */ + char mpd_filename[GF_MAX_PATH]; + /* segment duration */ + int seg_dur; + /* fragment duration */ + int frag_dur; + /* Exit signal emitting from user to end the program */ + volatile int exit_signal; + /* List of entries for video in configuration file */ + GF_List *video_lst; + /* List of entries for audio in configuration file */ + GF_List *audio_lst; + /* Indicates that the system is live */ + /* List of video input sources */ + GF_List *vsrc; + /* List of audio input sources */ + GF_List *asrc; + //int live; + /* Indicates that the system is live from a media input */ + //int live_media; + /* The mode of the system: ON_DEMAND, LIVE_CAMERA, LIVE_MEDIA */ + int mode; + /* Does not loop on input */ + int no_loop; + /* MPD AvailabilityStartTime offset in milliseconds. Default is 1000 milliseconds delay */ + int ast_offset; + /* MPD time shift buffer depth in seconds */ + int time_shift; + /* MPD minimumUpdatePeriod in seconds */ + int minimum_update_period; + /* Send message on port 1234 once fragment is ready */ + int send_message; + /* End of Segment Box name */ + u32 seg_marker; + /* GDR */ + int gdr; + /* GOP size in frames - 0 means framerate (1 sec)*/ + int gop_size; + /* MPD min buffer time */ + float min_buffer_time; + /* MPD BaseURL*/ + char base_url[GF_MAX_PATH]; + /* output directory name */ + char out_dir[GF_MAX_PATH]; + /* switch source configuration file */ + //char switch_cfg_filename[GF_MAX_PATH]; + FILE *logfile; + TaskList task_list; + /*dynamic ast*/ + int use_dynamic_ast; + /*insert UTC */ + int insert_utc; + + Bool use_source_timing; + Bool use_mem_track; +} CmdData; + +/* + * Initilize the command data structure + * + * @param cmd_data [out] structure to be initialize + */ +void dc_cmd_data_init(CmdData *cmd_data); + +/* + * Destroy the command data structure + * + * @param cmd_data [out] structure to be destroyed + */ +void dc_cmd_data_destroy(CmdData *cmd_data); + +/* + * Parse command line + * + * @param argc [in] number of arguments + * @param argv [in] a list of strings each containing one argument + * @param cmd_data [out] the data structure to fill + */ +int dc_parse_command(int argc, char **argv, CmdData *cmd_data); + +#endif /* CMD_DATA_H_ */ diff --git a/applications/dashcast/controler.c b/applications/dashcast/controler.c new file mode 100644 index 0000000..08d5601 --- /dev/null +++ b/applications/dashcast/controler.c @@ -0,0 +1,1599 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "controler.h" + + +#if (!defined(__DARWIN__) && !defined(__APPLE__)) +# include +#endif + +#include + +#if defined(__GNUC__) +# include +# include +#elif defined(WIN32) +# include +# include +# define suseconds_t long +#else +# error +#endif + +#include + +typedef struct { + int segnum; + u64 utc_time, ntpts; +} segtime; + + +//#define MAX_SOURCE_NUMBER 20 +#define DASHER 0 +#define FRAGMENTER 0 +//#define DEBUG 1 + +//#define VIDEO_MUXER FFMPEG_VIDEO_MUXER +//#define VIDEO_MUXER RAW_VIDEO_H264 +//#define VIDEO_MUXER GPAC_VIDEO_MUXER +#define VIDEO_MUXER GPAC_INIT_VIDEO_MUXER_AVC1 +//#define VIDEO_MUXER GPAC_INIT_VIDEO_MUXER_AVC3 + +//#define AUDIO_MUXER FFMPEG_AUDIO_MUXER +//#define AUDIO_MUXER GPAC_AUDIO_MUXER +#define AUDIO_MUXER GPAC_INIT_AUDIO_MUXER + +#define DASHCAST_PRINT + +#define AUDIO_FRAME_SIZE 1024 + + +void optimize_seg_frag_dur(int *seg, int *frag) +{ + int min_rem; + int seg_nb = *seg; + int frag_nb = *frag; + if (!frag_nb) frag_nb = 1; + + min_rem = seg_nb % frag_nb; + + if (seg_nb % (frag_nb + 1) < min_rem) { + min_rem = seg_nb % (frag_nb + 1); + *seg = seg_nb; + *frag = frag_nb + 1; + } + + if ((seg_nb + 1) % frag_nb < min_rem) { + min_rem = (seg_nb + 1) % frag_nb; + *seg = seg_nb + 1; + *frag = frag_nb; + } + + if ((seg_nb + 1) % (frag_nb + 1) < min_rem) { + min_rem = (seg_nb + 1) % (frag_nb + 1); + *seg = seg_nb + 1; + *frag = frag_nb + 1; + } + + *seg -= min_rem; +} + +Bool change_source_thread(void *params) +{ + int ret = 0; + return ret; +} + +u32 send_frag_event(void *params) +{ + int ret; + //int status; + char buff[GF_MAX_PATH]; + ThreadParam *th_param = (ThreadParam*)params; + CmdData *cmd_data = th_param->in_data; + MessageQueue *mq = th_param->mq; + + while (1) { + if (cmd_data->exit_signal) { + break; + } + + ret = dc_message_queue_get(mq, (void*) buff); + if (ret > 0) { + fprintf(stdout, "Message received: %s\n", buff); + } + } + + return 0; +} + +static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, const VideoDataConf *video_data_conf, const char *presentation_duration, const char *availability_start_time, const char *time_shift, const int segnum, const int ast_offset) +{ + u32 i = 0; + int audio_seg_dur = 0, video_seg_dur = 0, audio_frag_dur = 0, video_frag_dur = 0; + int audio_frame_size = AUDIO_FRAME_SIZE; + FILE *f; + + char name[GF_MAX_PATH]; + snprintf(name, sizeof(name), "%s/%s", cmddata->out_dir, cmddata->mpd_filename); + + if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { + audio_data_conf = gf_list_get(cmddata->audio_lst, 0); + audio_seg_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->seg_dur / 1000.0)); + audio_frag_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->frag_dur / 1000.0)); + optimize_seg_frag_dur(&audio_seg_dur, &audio_frag_dur); + } + + if (strcmp(cmddata->video_data_conf.filename, "") != 0) { + video_data_conf = gf_list_get(cmddata->video_lst, 0); + video_seg_dur = (int)(video_data_conf->framerate * (cmddata->seg_dur / 1000.0)); + video_frag_dur = (int)(video_data_conf->framerate * (cmddata->frag_dur / 1000.0)); + optimize_seg_frag_dur(&video_seg_dur, &video_frag_dur); + } + + f = gf_fopen(name, "w"); + //TODO: if (!f) ... + + // time_t t = time(NULL); + // time_t t2 = t + 2; + // t += (2 * (cmddata->seg_dur / 1000.0)); + // tm = *gmtime(&t2); + // snprintf(availability_start_time, "%d-%d-%dT%d:%d:%dZ", tm.tm_year + 1900, + // tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + // fprintf(stdout, "%s \n", availability_start_time); + + fprintf(f, "\n"); + fprintf(f, "mode == ON_DEMAND) ? "mediaPresentationDuration" : "availabilityStartTime", + (cmddata->mode == ON_DEMAND) ? presentation_duration : availability_start_time, + cmddata->min_buffer_time, time_shift, + (cmddata->mode == ON_DEMAND) ? "static" : "dynamic"); + if (cmddata->minimum_update_period > 0 ) { + fprintf(f, " minimumUpdatePeriod=\"PT%dS\"", cmddata->minimum_update_period); + } + fprintf(f, ">\n"); + fprintf(f, + " \n" + " %s\n" + " \n", cmddata->mpd_filename); + + if (strcmp(cmddata->base_url, "") != 0) { + fprintf(f, " %s\n", cmddata->base_url); + } + + fprintf(f, " \n"); + + if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { + fprintf(f, " \n"); + + fprintf(f, + " \n"); + + fprintf(f, + " samplerate, audio_seg_dur * audio_frame_size, segnum); + + if (ast_offset<0) { + fprintf(f, " availabilityTimeOffset=\"%g\"", -ast_offset/1000.0); + } + fprintf(f, "/>\n"); + + + + for (i = 0; i < gf_list_count(cmddata->audio_lst); i++) { + audio_data_conf = gf_list_get(cmddata->audio_lst, i); + fprintf(f, + " \n" + " \n", audio_data_conf->filename, audio_data_conf->samplerate, audio_data_conf->bitrate); + } + + fprintf(f, " \n"); + } + + if (strcmp(cmddata->video_data_conf.filename, "") != 0) { + fprintf(f, " \n"); + + fprintf(f, + " framerate, video_seg_dur, segnum); + + + if (ast_offset<0) { + fprintf(f, " availabilityTimeOffset=\"%g\"", -ast_offset/1000.0); + } + fprintf(f, "/>\n"); + + for (i = 0; i < gf_list_count(cmddata->video_lst); i++) { + video_data_conf = gf_list_get(cmddata->video_lst, i); + fprintf(f, " \n" + " \n", video_data_conf->filename, + VIDEO_MUXER == GPAC_INIT_VIDEO_MUXER_AVC1 ? video_data_conf->codec6381 : "avc3", + video_data_conf->width, video_data_conf->height, video_data_conf->framerate, + video_data_conf->bitrate); + } + + fprintf(f, " \n"); + } + + fprintf(f, " \n"); + + fprintf(f, "\n"); + + gf_fclose(f); +} + +static u32 mpd_thread(void *params) +{ + ThreadParam *th_param = (ThreadParam*)params; + CmdData *cmddata = th_param->in_data; + MessageQueue *mq = th_param->mq; + char availability_start_time[GF_MAX_PATH]; + char presentation_duration[GF_MAX_PATH]; + char time_shift[GF_MAX_PATH] = ""; + AudioDataConf *audio_data_conf = NULL; + VideoDataConf *video_data_conf = NULL; + struct tm ast_time; + + segtime main_seg_time; + Bool first = GF_TRUE; + main_seg_time.segnum = 0; + main_seg_time.utc_time = 0; + main_seg_time.ntpts = 0; + + if (cmddata->mode == LIVE_CAMERA || cmddata->mode == LIVE_MEDIA) { + while (1) { + u32 msecs; + time_t t; + segtime seg_time; + seg_time.segnum = 0; + seg_time.utc_time = 0; + + if (cmddata->exit_signal) { + break; + } + + if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { + dc_message_queue_get(mq, &seg_time); + } + + if (strcmp(cmddata->video_data_conf.filename, "") != 0) { + if (dc_message_queue_get(mq, &seg_time)<0) { + continue; + } + + if (cmddata->ast_offset>0) { + seg_time.utc_time += cmddata->ast_offset; + } + + if (cmddata->use_dynamic_ast) { + main_seg_time = seg_time; + } else { + //get the last notification of AST + if (first) { + if (seg_time.segnum) { + first = GF_FALSE; + } else { + main_seg_time = seg_time; + } + } else { + assert(seg_time.segnum); + } + } + } + + + t = (seg_time.ntpts >> 32) - GF_NTP_SEC_1900_TO_1970; + msecs = (u32) ( (seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) ); + ast_time = *gmtime(&t); + fprintf(stdout, "Generating MPD at %d-%02d-%02dT%02d:%02d:%02d.%03dZ\n", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs); + + t = (main_seg_time.ntpts >> 32) - GF_NTP_SEC_1900_TO_1970; + msecs = (u32) ( (main_seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) ); + ast_time = *gmtime(&t); + sprintf(availability_start_time, "%d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs); + fprintf(stdout, "StartTime: %s - startNumber %d - last number %d\n", availability_start_time, main_seg_time.segnum+1, seg_time.segnum+1); + + if (cmddata->time_shift != -1) { + int ts, h, m, s; + ts = cmddata->time_shift; + h = ts / 3600; + ts = ts % 3600; + m = ts / 60; + s = ts % 60; + snprintf(time_shift, sizeof(time_shift), "timeShiftBufferDepth=\"PT%02dH%02dM%02dS\"", h, m, s); + } + + dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, time_shift, main_seg_time.segnum+1, cmddata->ast_offset); + } + } else { + + int a_dur = 0; + int v_dur = 0; + + if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { + dc_message_queue_get(mq, &a_dur); + } + + if (strcmp(cmddata->video_data_conf.filename, "") != 0) { + dc_message_queue_get(mq, &v_dur); + } + + { + int dur, h, m, s, ms; + dur = v_dur > a_dur ? v_dur : a_dur; + h = dur / 3600000; + dur = dur % 3600000; + m = dur / 60000; + dur = dur % 60000; + s = dur / 1000; + ms = dur % 1000; + snprintf(presentation_duration, sizeof(presentation_duration), "PT%02dH%02dM%02d.%03dS", h, m, s, ms); + fprintf(stdout, "Duration: %s\n", presentation_duration); + } + + dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, time_shift, 0, cmddata->ast_offset); + } + + return 0; +} + +u32 delete_seg_thread(void *params) +{ + int ret; + ThreadParam *th_param = (ThreadParam*)params; + CmdData *cmd_data = th_param->in_data; + MessageQueue *mq = th_param->mq; + + char buff[GF_MAX_PATH]; + + while (1) { + ret = dc_message_queue_get(mq, (void*) buff); + if (ret > 0) { + int status; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Message received: %s\n", buff)); + status = unlink(buff); + if (status != 0) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Unable to delete the file %s\n", buff)); + } + } + + if (cmd_data->exit_signal) { + break; + } + } + + return 0; +} + +Bool fragmenter_thread(void *params) +{ + int ret; + ThreadParam *th_param = (ThreadParam*)params; + CmdData *cmd_data = th_param->in_data; + MessageQueue *mq = th_param->mq; + + char buff[GF_MAX_PATH]; + + while (1) { + ret = dc_message_queue_get(mq, (void*) buff); + if (ret > 0) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Message received: %s\n", buff)); + } + + if (cmd_data->exit_signal) { + break; + } + } + + return 0; +} + +Bool dasher_thread(void *params) +{ +// int i; +// ThreadParam *th_param = (ThreadParam *) params; +// CmdData *cmd_data = th_param->in_data; +// +// char sz_mpd[GF_MAX_PATH]; +// GF_DashSegmenterInput *dash_inputs; +// u32 nb_dash_inputs = 0; +// Bool use_url_template = 0; +// GF_Err e; +// s32 subsegs_per_sidx = 0; +// Bool daisy_chain_sidx = 0; +// char *seg_ext = NULL; +// const char *dash_title = NULL; +// const char *dash_source = NULL; +// const char *dash_more_info = NULL; +// char *tmpdir = NULL, *cprt = NULL, *seg_name = NULL; +// char **mpd_base_urls = NULL; +// u32 nb_mpd_base_urls = 0; +// Bool single_segment = 0; +// +// Bool single_file = 0; +// GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_INBAND; +// Bool seg_at_rap = 0; +// Bool frag_at_rap = 0; +// +// Double interleaving_time = 0.0; +// u32 time_shift_depth = 0; +// Double dash_duration = 0.0, dash_subduration = 0.0; +// u32 mpd_update_time = 0; +// +// +// GF_DashProfile dash_profile = GF_DASH_PROFILE_UNKNOWN; +// u32 dash_dynamic = 0; +// GF_Config *dash_ctx = NULL; +// +// int video_list_size = gf_list_count(cmd_data->video_lst); +// int audio_list_size = gf_list_count(cmd_data->audio_lst); +// nb_dash_inputs = video_list_size + audio_list_size; +// +// dash_inputs = gf_malloc(nb_dash_inputs * sizeof(GF_DashSegmenterInput)); +// +// for (i = 0; i < video_list_size; i++) { +// +// VideoDataConf *video_data_conf = gf_list_get(cmd_data->video_lst, i); +// dash_inputs[i].file_name = video_data_conf->filename; +// snprintf(dash_inputs[i].representationID, "%d", i); +// strcpy(dash_inputs[i].periodID, ""); +// strcpy(dash_inputs[i].role, ""); +// +// } +// +// for (i = 0; i < audio_list_size; i++) { +// +// AudioDataConf *audio_data_conf = gf_list_get(cmd_data->audio_lst, i); +// dash_inputs[i + video_list_size].file_name = audio_data_conf->filename; +// snprintf(dash_inputs[i + video_list_size].representationID, "%d", +// i + video_list_size); +// strcpy(dash_inputs[i + video_list_size].periodID, ""); +// strcpy(dash_inputs[i + video_list_size].role, ""); +// +// } +// +// dash_profile = cmd_data->live ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_MAIN; +// strncpy(sz_mpd, cmd_data->mpd_filename, GF_MAX_PATH-1); +// +// dash_duration = cmd_data->dash_dur ? cmd_data->dash_dur / 1000 : 1; +// +// if (cmd_data->live) { +// dash_ctx = gf_cfg_new(NULL, NULL); +// } +// +// if (!dash_dynamic) { +// time_shift_depth = 0; +// mpd_update_time = 0; +// } else if ((dash_profile >= GF_DASH_PROFILE_MAIN) && !use_url_template +// && !mpd_update_time) { +// /*use a default MPD update of dash_duration sec*/ +// mpd_update_time = (u32) ( +// dash_subduration ? dash_subduration : dash_duration); +// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Using default MPD refresh of %d seconds\n", +// mpd_update_time); +// } +// +// if (cmd_data->live) +// gf_sleep(dash_duration * 1000); +// +// while (1) { +// +// //TODO Signiture of this API has changed! +// /* +// e = gf_dasher_segment_files(sz_mpd, dash_inputs, nb_dash_inputs, +// dash_profile, dash_title, dash_source, cprt, dash_more_info, +// (const char **) mpd_base_urls, nb_mpd_base_urls, +// use_url_template, single_segment, single_file, +// bitstream_switching_mode, seg_at_rap, dash_duration, seg_name, +// seg_ext, interleaving_time, subsegs_per_sidx, daisy_chain_sidx, +// frag_at_rap, tmpdir, dash_ctx, dash_dynamic, mpd_update_time, +// time_shift_depth, dash_subduration); +// +// if (e) { +// fprintf(stdout, "Error while segmenting.\n"); +// break; +// } +// */ +// +// if (!cmd_data->live) +// break; +// +// u32 sleefor = gf_dasher_next_update_time(dash_ctx, mpd_update_time); +// +// if (cmd_data->exit_signal) { +// break; +// } +// +// if (sleefor) { +// if (dash_dynamic != 2) { +// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("sleep for %d ms\n", sleefor); +// gf_sleep(sleefor); +// } +// } +// +// } + + return 0; +} + +static u32 keyboard_thread(void *params) +{ + + ThreadParam *th_param = (ThreadParam*)params; + CmdData *in_data = th_param->in_data; + char c; + + while (1) { + if (gf_prompt_has_input()) { + c = gf_prompt_get_char(); + if (c == 'q' || c == 'Q') { + in_data->exit_signal = 1; + break; + } + } + + if (in_data->exit_signal) { + break; + } + + gf_sleep(100); + } + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Keyboard thread exit\n")); + return 0; +} + +u32 video_decoder_thread(void *params) +{ +#ifdef DASHCAST_PRINT + int i = 0; +#endif + int ret; + int source_number = 0; + + //int first_time = 1; + struct timeval time_start, time_end, time_wait; + VideoThreadParam *thread_params = (VideoThreadParam *) params; + + CmdData *in_data = thread_params->in_data; + VideoInputData *video_input_data = thread_params->video_input_data; + VideoInputFile **video_input_file = thread_params->video_input_file; + + suseconds_t total_wait_time = (int) (1000000.0 / (double) in_data->video_data_conf.framerate); + suseconds_t pick_packet_delay, select_delay = 0, real_wait, other_delays = 2; + + Task t; + //fprintf(stdout, "wait time : %f\n", total_wait_time); + + if (!gf_list_count(in_data->video_lst)) + return 0; + + while (1) { + dc_task_get_current(&in_data->task_list, &t); + source_number = t.source_number; + + //fprintf(stdout, "sourcenumber: %d\n", source_number); + + if (video_input_file[source_number]->mode == LIVE_MEDIA) { + gf_gettimeofday(&time_start, NULL); + } + + ret = dc_video_decoder_read(video_input_file[source_number], video_input_data, source_number, in_data->use_source_timing, (in_data->mode == LIVE_CAMERA) ? 1 : 0, (const int *) &in_data->exit_signal); +#ifdef DASHCAST_PRINT + fprintf(stdout, "Read video frame %d\r", i++); + fflush(stdout); +#endif + if (ret == -2) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video reader has no more frame to read.\n")); + break; + } + if (ret == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occurred while reading video frame.\n")); + break; + } + + if (in_data->exit_signal) { + dc_video_input_data_end_signal(video_input_data); + break; + } + + if (video_input_file[source_number]->mode == LIVE_MEDIA) { + gf_gettimeofday(&time_end, NULL); + pick_packet_delay = ((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec; + time_wait.tv_sec = 0; + real_wait = total_wait_time - pick_packet_delay - select_delay - other_delays; + time_wait.tv_usec = real_wait; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("delay: %ld = %ld - %ld\n", time_wait.tv_usec, total_wait_time, pick_packet_delay)); + + gf_gettimeofday(&time_start, NULL); + select(0, NULL, NULL, NULL, &time_wait); + gf_gettimeofday(&time_end, NULL); + + select_delay = (((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec) - real_wait; + } + } + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Video decoder is exiting...\n")); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video decoder thread exit\n")); + return 0; +} + +u32 audio_decoder_thread(void *params) +{ +#ifdef DASHCAST_PRINT + int i = 0; +#endif + int ret; + struct timeval time_start, time_end, time_wait; + AudioThreadParam *thread_params = (AudioThreadParam*)params; + + CmdData *in_data = thread_params->in_data; + AudioInputData *audio_input_data = thread_params->audio_input_data; + AudioInputFile *audio_input_file = thread_params->audio_input_file; + + suseconds_t pick_packet_delay, select_delay = 0, real_wait, other_delays = 1; + suseconds_t total_wait_time; + if (in_data->audio_data_conf.samplerate < 1024) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error: invalid audio sample rate: %d\n", in_data->audio_data_conf.samplerate)); + dc_audio_inout_data_end_signal(audio_input_data); + //FIXME: deadlock on the mpd thread. Reproduce with big_buck_bunny.mp4. + return 1; + } + total_wait_time = (int) (1000000.0 / (in_data->audio_data_conf.samplerate / (double) AUDIO_FRAME_SIZE)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("wait time : %ld\n", total_wait_time)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("sample-rate : %ld\n", in_data->audio_data_conf.samplerate)); + + if (!gf_list_count(in_data->audio_lst)) + return 0; + + while (1) { + if (audio_input_file->mode == LIVE_MEDIA) { + gf_gettimeofday(&time_start, NULL); + } + + ret = dc_audio_decoder_read(audio_input_file, audio_input_data); +#ifdef DASHCAST_PRINT + fprintf(stdout, "Read audio frame %d\r", i++); + fflush(stdout); +#endif + if (ret == -2) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio decoder has no more frame to read.\n")); + break; + } + if (ret == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occurred while reading audio frame.\n")); + break; + } + + if (in_data->exit_signal) { + dc_audio_inout_data_end_signal(audio_input_data); + break; + } + + if (audio_input_file->mode == LIVE_MEDIA) { + gf_gettimeofday(&time_end, NULL); + pick_packet_delay = ((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec; + time_wait.tv_sec = 0; + real_wait = total_wait_time - pick_packet_delay - select_delay - other_delays; + time_wait.tv_usec = real_wait; + + gf_gettimeofday(&time_start, NULL); + select(0, NULL, NULL, NULL, &time_wait); + gf_gettimeofday(&time_end, NULL); + + select_delay = (((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec) - real_wait; + } + } + + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio decoder is exiting...\n")); + return 0; +} + +u32 video_scaler_thread(void *params) +{ + int ret; + VideoThreadParam *thread_params = (VideoThreadParam *) params; + CmdData *in_data = thread_params->in_data; + VideoInputData *video_input_data = thread_params->video_input_data; + VideoScaledData *video_scaled_data = thread_params->video_scaled_data; + + if (!gf_list_count(in_data->video_lst)) + return 0; + + while (1) { + ret = dc_video_scaler_scale(video_input_data, video_scaled_data); + if (ret == -2) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video scaler has no more frame to read.\n")); + break; + } + } + + dc_video_scaler_end_signal(video_scaled_data); + + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video scaler thread exit\n")); + return 0; +} + +u32 video_encoder_thread(void *params) +{ + int ret, shift, frame_nb, seg_frame_max, frag_frame_max, seg_nb = 0, loss_state = 0, quit = 0, real_video_seg_dur; + char name_to_delete[GF_MAX_PATH], name_to_send[GF_MAX_PATH]; + u64 start_utc, seg_utc; + segtime time_at_segment_start; + VideoMuxerType muxer_type = VIDEO_MUXER; + VideoThreadParam *thread_params = (VideoThreadParam*)params; + u32 sec, frac; + Bool init_mpd = GF_FALSE; + CmdData *in_data = thread_params->in_data; + int video_conf_idx = thread_params->video_conf_idx; + VideoDataConf *video_data_conf = gf_list_get(in_data->video_lst, video_conf_idx); + + VideoScaledData *video_scaled_data = thread_params->video_scaled_data; + int video_cb_size = (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) ? 1 : VIDEO_CB_DEFAULT_SIZE; + VideoOutputFile out_file; + + MessageQueue *mq = thread_params->mq; + MessageQueue *delete_seg_mq = thread_params->delete_seg_mq; + MessageQueue *send_seg_mq = thread_params->send_seg_mq; +#ifndef FRAGMENTER + MessageQueue *mq = thread_params->mq; +#endif + + if (!gf_list_count(in_data->video_lst)) + return 0; + + seg_frame_max = (int)(video_data_conf->framerate * (float) (in_data->seg_dur / 1000.0)); + frag_frame_max = (int)(video_data_conf->framerate * (float) (in_data->frag_dur / 1000.0)); + optimize_seg_frag_dur(&seg_frame_max, &frag_frame_max); + + real_video_seg_dur = (int) (seg_frame_max * 1000.0 / (float) video_data_conf->framerate); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[video_encoder] seg_frame_max=%d, frag_frame_max=%d, real_video_seg_dur=%d ms\n", seg_frame_max, frag_frame_max, real_video_seg_dur)); + + + if (seg_frame_max <= 0) + seg_frame_max = -1; + + shift = 0; + if (in_data->use_source_timing) { + //ugly patch ... + shift = 1000; + while (!video_scaled_data->frame_duration && shift) { + gf_sleep(1); + shift--; + } + shift = (u32) video_scaled_data->frame_duration; + } + if (dc_video_muxer_init(&out_file, video_data_conf, muxer_type, seg_frame_max, frag_frame_max, in_data->seg_marker, in_data->gdr, in_data->seg_dur, in_data->frag_dur, shift, in_data->gop_size, video_cb_size) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot init output video file.\n")); + in_data->exit_signal = 1; + return -1; + } + + if (dc_video_encoder_open(&out_file, video_data_conf, in_data->use_source_timing, video_scaled_data->sar) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video stream.\n")); + in_data->exit_signal = 1; + return -1; + } + + if (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) { + init_mpd = GF_TRUE; + } + + + time_at_segment_start.ntpts = 0; + start_utc = gf_net_get_utc(); + seg_utc = 0; + while (1) { + frame_nb = 0; + //log time at segment start, because segment availabilityStartTime is computed from AST anchor + segment duration + //logging at the end of the segment production will induce one segment delay + time_at_segment_start.segnum = seg_nb; + time_at_segment_start.utc_time = gf_net_get_utc(); + gf_net_get_ntp(&sec, &frac); + +#ifndef GPAC_DISABLE_LOG + if (gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_INFO)) { + if (time_at_segment_start.ntpts) { + u32 ref_sec, ref_frac; + Double tr, t; + ref_sec = (time_at_segment_start.ntpts>>32) & 0xFFFFFFFFULL; + ref_frac = (u32) (time_at_segment_start.ntpts & 0xFFFFFFFFULL); + tr = ref_sec * 1000.0; + tr += ref_frac*1000.0 /0xFFFFFFFF; + t = sec * 1000.0; + t += frac*1000.0 /0xFFFFFFFF; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] NTP diff since last segment start in msec is %f\n", t - tr)); + + } + } +#endif + + time_at_segment_start.ntpts = sec; + time_at_segment_start.ntpts <<= 32; + time_at_segment_start.ntpts |= frac; + + //force writing MPD before any encoding happens (eg don't wait for the end of the first segment) + if (init_mpd) { + init_mpd = GF_FALSE; + dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start)); + } + + assert(! out_file.segment_started); + + if (dc_video_muxer_open(&out_file, in_data->out_dir, video_data_conf->filename, seg_nb+1) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video file.\n")); + in_data->exit_signal = 1; + return -1; + } +// fprintf(stdout, "Header size: %d\n", ret); + while (1) { + u64 ntpts = gf_net_get_ntp_ts(); + + //we have the RAP already encoded, skip coder + if (loss_state == 2) { + ret = 1; + loss_state = 0; + } else { + ret = dc_video_encoder_encode(&out_file, video_scaled_data); + } + + if (ret == -2) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video encoder has no more data to encode.\n")); + quit = 1; + break; + } + if (ret == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while writing video frame.\n")); + quit = 1; + break; + } + + if (ret > 0) { + int r; + + /*resync at first RAP: flush current broken segment and restart next one on rap*/ + if ((loss_state==1) && out_file.codec_ctx->coded_frame->key_frame) { + loss_state = 2; + break; + } + + r = dc_video_muxer_write(&out_file, frame_nb, in_data->insert_utc ? ntpts : 0); + if (r < 0) { + quit = 1; + in_data->exit_signal = 1; + break; + } else if (r == 1) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("fragment is written!\n")); + if (in_data->send_message == 1) { + snprintf(name_to_send, sizeof(name_to_send), "%s/%s_%d_gpac.m4s", in_data->out_dir, video_data_conf->filename, seg_nb); + dc_message_queue_put(send_seg_mq, name_to_send, sizeof(name_to_send)); + } + + break; + } + + frame_nb++; + } + } + + dc_video_muxer_close(&out_file); + +#ifndef FRAGMENTER + dc_message_queue_put(mq, video_data_conf->filename, sizeof(video_data_conf->filename)); +#endif + + // If system is live, + // Send the time that a segment is available to MPD generator thread. + if (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) { + //check we don't loose sync + int diff; + int seg_diff; + seg_utc = gf_net_get_utc(); + diff = (int) (seg_utc - start_utc); + + //if seg UTC is after next segment UTC (current ends at seg_nb+1, next at seg_nb+2), adjust numbers + if (diff > (seg_nb+2) * real_video_seg_dur) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", out_file.rep_id, diff, seg_nb)); + + while (diff > (seg_nb+2) * real_video_seg_dur) { + seg_nb++; + + //do a rough estimate of losses to adjust timing... + if (! in_data->use_source_timing) { + out_file.first_dts_in_fragment += out_file.codec_ctx->time_base.den; + } + } + //wait for RAP to cut next segment + loss_state = 1; + } else { +#define SYNC_SAFE 800 + + seg_diff = diff; + seg_diff -= (seg_nb+1) * real_video_seg_dur; + if (seg_diff > SYNC_SAFE) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff at segment close: %d is higher than cumulated segment duration %d (diff %d) - frame rate is probably not correct!\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff)); + } + else if (seg_diff < -SYNC_SAFE) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff at segment close: %d is lower than cumulated segment duration %d (diff %d) - frame rate is probably not correct or frames were lost!\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff)); + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff at segment close: %d - cumulated segment duration %d (diff %d)\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff)); + } + } + + //time_t t = time(NULL); + dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start)); + } + + if ((in_data->time_shift != -1)) { + shift = 1000 * in_data->time_shift / in_data->seg_dur; + if (seg_nb - shift>=0) { + snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, video_data_conf->filename, (seg_nb - shift)); + dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete)); + } + } + + seg_nb++; + + if (quit) + break; + } + + // If system is not live, + // Send the duration of the video + if (in_data->mode == ON_DEMAND) { + if (thread_params->video_conf_idx == 0) { + int dur = (seg_nb * seg_frame_max * 1000) / video_data_conf->framerate; + int dur_tot = (out_file.codec_ctx->frame_number * 1000) + / video_data_conf->framerate; + if (dur > dur_tot) + dur = dur_tot; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Duration: %d \n", dur)); + dc_message_queue_put(mq, &dur, sizeof(dur)); + } + } + + /* Close output video file */ + dc_video_encoder_close(&out_file); + + dc_video_muxer_free(&out_file); + + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video encoder thread exit\n")); + return 0; +} + +u32 audio_encoder_thread(void *params) +{ + int ret, exit_loop = 0, quit = 0, seg_nb = 0, frame_per_seg, frame_per_frag, frame_nb, shift, real_audio_seg_dur; + //int seg_frame_max; + //int frag_frame_max; + //int audio_frame_size = AUDIO_FRAME_SIZE; + char name_to_delete[GF_MAX_PATH]; + u64 start_utc, seg_utc; + + AudioMuxerType muxer_type = AUDIO_MUXER; + AudioThreadParam *thread_params = (AudioThreadParam *) params; + + CmdData *in_data = thread_params->in_data; + int audio_conf_idx = thread_params->audio_conf_idx; + AudioDataConf *audio_data_conf = gf_list_get(in_data->audio_lst, audio_conf_idx); + + AudioInputData *audio_input_data = thread_params->audio_input_data; + AudioOutputFile audio_output_file; + + MessageQueue *mq = thread_params->mq; + MessageQueue *delete_seg_mq = thread_params->delete_seg_mq; +#ifndef FRAGMENTER + MessageQueue *mq = thread_params->mq; +#endif + + if (!gf_list_count(in_data->audio_lst)) + return 0; + + //seg_frame_max = audio_data_conf->samplerate + // * (float) (in_data->seg_dur / 1000.0); + + //frag_frame_max = audio_data_conf->samplerate * (float) (in_data->frag_dur / 1000.0); + //if (seg_frame_max <= 0) + // seg_frame_max = -1; + + if (dc_audio_encoder_open(&audio_output_file, audio_data_conf) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio stream.\n")); + in_data->exit_signal = 1; + return -1; + } + + frame_per_seg = (int)((audio_data_conf->samplerate / (double) audio_output_file.codec_ctx->frame_size) * (in_data->seg_dur / 1000.0)); + frame_per_frag = (int)((audio_data_conf->samplerate / (double) audio_output_file.codec_ctx->frame_size) * (in_data->frag_dur / 1000.0)); + optimize_seg_frag_dur(&frame_per_seg, &frame_per_frag); + + real_audio_seg_dur = (int) (frame_per_seg * (double) audio_output_file.codec_ctx->frame_size * 1000.0 / (double) audio_data_conf->samplerate); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[audio_encoder] frame_per_seg=%d, frame_per_frag=%d, real_audio_seg_dur=%d ms\n", frame_per_seg, frame_per_frag, real_audio_seg_dur) ); + + if (dc_audio_muxer_init(&audio_output_file, audio_data_conf, muxer_type, frame_per_seg, frame_per_frag, in_data->seg_marker) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot init output audio.\n")); + in_data->exit_signal = 1; + return -1; + } + + start_utc = gf_net_get_utc(); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[audio_encoder] start_utc="LLU"\n", start_utc)); + seg_utc = 0; + while (1) { + frame_nb = 0; + quit = 0; + if (dc_audio_muxer_open(&audio_output_file, in_data->out_dir, audio_data_conf->filename, seg_nb+1) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio.\n")); + in_data->exit_signal = 1; + return -1; + } + + while (1) { + exit_loop = 0; +// if (frame_per_seg > 0) { +// if (frame_nb == frame_per_seg) { +// +// //if (dc_audio_encoder_flush(&audio_output_file, audio_input_data) == 0) { +// // dc_audio_muxer_write(&audio_output_file); +// // frame_nb++;//= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples; +// //} +// +// exit_loop = 1; +// break; +// } +// } + + ret = dc_audio_encoder_read(&audio_output_file, audio_input_data); + if (ret == -2) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder has no more data to encode.\n")); + //if (dc_audio_encoder_flush(&audio_output_file, audio_input_data) == 0) { + // dc_audio_muxer_write(&audio_output_file); + // frame_nb++;//= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples; + //} + quit = 1; + break; + } + + while (1) { + ret = dc_audio_encoder_encode(&audio_output_file, audio_input_data); + if (ret == 1) { + break; + } + if (ret == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while encoding audio frame.\n")); + quit = 1; + break; + } + + ret = dc_audio_muxer_write(&audio_output_file, frame_nb); + if (ret == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while writing audio frame.\n")); + quit = 1; + break; + } + + if (ret == 1) { + exit_loop = 1; + break; + } + + frame_nb++; //= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples; + } + + if (exit_loop || quit) + break; + } + + dc_audio_muxer_close(&audio_output_file); + +#ifndef FRAGMENTER + dc_message_queue_put(mq, audio_data_conf->filename, sizeof(audio_data_conf->filename)); +#endif + + // Send the time that a segment is available to MPD generator thread. + if (in_data->mode == LIVE_CAMERA || in_data->mode == LIVE_MEDIA) { + if (thread_params->audio_conf_idx == 0) { + segtime t; + + //check we don't loose sync + int diff; + seg_utc = gf_net_get_utc(); + diff = (int) (seg_utc - start_utc); + //if seg UTC is after next segment UTC (current ends at seg_nb+1, next at seg_nb+2), adjust numbers + if (diff > (seg_nb+2) * real_audio_seg_dur) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[audio_encoder] UTC diff %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", diff, seg_nb)); + while (diff > (seg_nb+2) * real_audio_seg_dur) { + seg_nb++; + } + } + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[audio_encoder] UTC diff %d - cumulated segment duration %d -> %d\n", diff, (seg_nb+1) * real_audio_seg_dur, diff - (seg_nb+1) * real_audio_seg_dur)); + t.segnum = seg_nb; + t.utc_time = gf_net_get_utc(); + //time_t t = time(NULL); + dc_message_queue_put(mq, &t, sizeof(t)); + } + } + + if (in_data->time_shift != -1) { + shift = 1000 * in_data->time_shift / in_data->seg_dur; + snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, audio_data_conf->filename, (seg_nb - shift)); + dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete)); + } + + seg_nb++; + + if (quit) + break; + } + + // If system is not live, + // Send the duration of the video + if (in_data->mode == ON_DEMAND) { + if (thread_params->audio_conf_idx == 0) { + int dur = (seg_nb * audio_output_file.codec_ctx->frame_size * frame_per_seg * 1000) / audio_data_conf->samplerate; + int dur_tot = (audio_output_file.codec_ctx->frame_number * audio_output_file.codec_ctx->frame_size * 1000) / audio_data_conf->samplerate; + if (dur > dur_tot) + dur = dur_tot; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Duration: %d \n", dur)); + dc_message_queue_put(mq, &dur, sizeof(dur)); + } + } + + dc_audio_muxer_free(&audio_output_file); + + /* Close output audio file */ + dc_audio_encoder_close(&audio_output_file); + + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder is exiting...\n")); + return 0; +} + +int dc_run_controler(CmdData *in_data) +{ + int ret = 0; + u32 video_cb_size = VIDEO_CB_DEFAULT_SIZE; + u32 i, j; + + ThreadParam keyboard_th_params; + ThreadParam mpd_th_params; + ThreadParam delete_seg_th_params; + ThreadParam send_frag_th_params; + + //Video parameters + VideoThreadParam vdecoder_th_params; + VideoThreadParam *vencoder_th_params = alloca(gf_list_count(in_data->video_lst) * sizeof(VideoThreadParam)); + VideoInputData video_input_data; + VideoInputFile *video_input_file[MAX_SOURCE_NUMBER]; + VideoScaledDataList video_scaled_data_list; + VideoThreadParam *vscaler_th_params = NULL; + + //Audio parameters + AudioThreadParam adecoder_th_params; + AudioThreadParam *aencoder_th_params = alloca(gf_list_count(in_data->audio_lst) * sizeof(AudioThreadParam)); + AudioInputData audio_input_data; + AudioInputFile audio_input_file; + +#ifndef DASHER + ThreadParam dasher_th_params; +#endif + +#ifndef FRAGMENTER + ThreadParam fragmenter_th_params; +#endif + + MessageQueue mq; + MessageQueue delete_seg_mq; + MessageQueue send_frag_mq; + + dc_register_libav(); + + for (i = 0; i < MAX_SOURCE_NUMBER; i++) + video_input_file[i] = gf_malloc(sizeof(VideoInputFile)); + + dc_message_queue_init(&mq); + dc_message_queue_init(&delete_seg_mq); + dc_message_queue_init(&send_frag_mq); + + memset(&audio_input_data, 0, sizeof(AudioInputData));; + memset(&audio_input_file, 0, sizeof(AudioInputFile)); + memset(&video_input_data, 0, sizeof(VideoInputData)); + + + if (in_data->mode == LIVE_CAMERA || in_data->mode == LIVE_MEDIA) + video_cb_size = 1; + + if (strcmp(in_data->video_data_conf.filename, "") != 0) { + dc_video_scaler_list_init(&video_scaled_data_list, in_data->video_lst); + vscaler_th_params = gf_malloc(video_scaled_data_list.size * sizeof(VideoThreadParam)); + + /* Open input video */ + if (dc_video_decoder_open(video_input_file[0], &in_data->video_data_conf, in_data->mode, in_data->no_loop, video_scaled_data_list.size) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input video.\n")); + ret = -1; + goto exit; + } + + if (dc_video_input_data_init(&video_input_data, /*video_input_file[0]->width, video_input_file[0]->height, + video_input_file[0]->pix_fmt,*/video_scaled_data_list.size, in_data->mode, MAX_SOURCE_NUMBER, video_cb_size) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize audio data.\n")); + ret = -1; + goto exit; + } + + /* open other input videos for source switching */ + for (i = 0; i < gf_list_count(in_data->vsrc); i++) { + VideoDataConf *video_data_conf = gf_list_get(in_data->vsrc, i); + if (dc_video_decoder_open(video_input_file[i + 1], video_data_conf, LIVE_MEDIA, 1, video_scaled_data_list.size) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input video.\n")); + ret = -1; + goto exit; + } + } + + for (i=0; ivsrc) + 1; i++) { + dc_video_input_data_set_prop(&video_input_data, i, video_input_file[i]->width, video_input_file[i]->height, in_data->video_data_conf.crop_x, in_data->video_data_conf.crop_y, video_input_file[i]->pix_fmt, video_input_file[i]->sar); + } + + for (i=0; ivsrc) + 1; j++) { + dc_video_scaler_data_set_prop(&video_input_data, video_scaled_data_list.video_scaled_data[i], j); + } + } + + /* Initialize video decoder thread */ + vdecoder_th_params.thread = gf_th_new("video_decoder_thread"); + + for (i=0; ivideo_lst); i++) + vencoder_th_params[i].thread = gf_th_new("video_encoder_thread"); + } + + /* When video and audio share the same source, open it once. This allow to read from unicast streams */ + if (!strcmp(in_data->video_data_conf.filename, in_data->audio_data_conf.filename)) { + audio_input_file.av_fmt_ctx = video_input_file[0]->av_fmt_ctx; + video_input_file[0]->av_fmt_ctx_ref_cnt++; + audio_input_file.av_pkt_list = video_input_file[0]->av_pkt_list = gf_list_new(); + audio_input_file.av_pkt_list_mutex = video_input_file[0]->av_pkt_list_mutex = gf_mx_new("Demux AVPackets List"); + } + + if (strcmp(in_data->audio_data_conf.filename, "") != 0) { + /* Open input audio */ + if (dc_audio_decoder_open(&audio_input_file, &in_data->audio_data_conf, in_data->mode, in_data->no_loop) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input audio.\n")); + ret = -1; + goto exit; + } + + if (dc_audio_input_data_init(&audio_input_data, in_data->audio_data_conf.channels, in_data->audio_data_conf.samplerate, gf_list_count(in_data->audio_lst), in_data->mode) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize audio data.\n")); + ret = -1; + goto exit; + } + + /* Initialize audio decoder thread */ + adecoder_th_params.thread = gf_th_new("audio_decoder_thread"); + + /* Initialize audio encoder threads */ + for (i = 0; i < gf_list_count(in_data->audio_lst); i++) + aencoder_th_params[i].thread = gf_th_new("video_encoder_thread"); + } + + /******** Keyboard controler Thread ********/ + + /* Initialize keyboard controller thread */ + keyboard_th_params.thread = gf_th_new("keyboard_thread"); + + /* Create keyboard controller thread */ + keyboard_th_params.in_data = in_data; + if (gf_th_run(keyboard_th_params.thread, keyboard_thread, (void *)&keyboard_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for keyboard_thread.\n")); + } + + /********************************************/ + + //Communication between decoder and audio encoder + for (i = 0; i < gf_list_count(in_data->audio_lst); i++) { + AudioDataConf *tmadata = gf_list_get(in_data->audio_lst, i); + tmadata->channels = in_data->audio_data_conf.channels; + tmadata->samplerate = in_data->audio_data_conf.samplerate; + } + + //Communication between decoder and video encoder + for (i = 0; i < gf_list_count(in_data->video_lst); i++) { + VideoDataConf *tmvdata = gf_list_get(in_data->video_lst, i); + tmvdata->framerate = in_data->video_data_conf.framerate; + if (in_data->use_source_timing) { + tmvdata->time_base = in_data->video_data_conf.time_base; + } + } + + /******** MPD Thread ********/ + + /* Initialize MPD generator thread */ + mpd_th_params.thread = gf_th_new("mpd_thread"); + + /* Create MPD generator thread */ + mpd_th_params.in_data = in_data; + mpd_th_params.mq = &mq; + if (gf_th_run(mpd_th_params.thread, mpd_thread, (void *)&mpd_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for mpd_thread.\n")); + } + + /****************************/ + + if (strcmp(in_data->video_data_conf.filename, "") != 0) { + /* Create video encoder threads */ + for (i=0; ivideo_lst); i++) { + VideoDataConf * video_data_conf = gf_list_get(in_data->video_lst, i); + + vencoder_th_params[i].in_data = in_data; + vencoder_th_params[i].video_conf_idx = i; + vencoder_th_params[i].video_scaled_data = dc_video_scaler_get_data(&video_scaled_data_list, video_data_conf->width, video_data_conf->height); + + vencoder_th_params[i].mq = &mq; + vencoder_th_params[i].delete_seg_mq = &delete_seg_mq; + vencoder_th_params[i].send_seg_mq = &send_frag_mq; + + if (gf_th_run(vencoder_th_params[i].thread, video_encoder_thread, (void*)&vencoder_th_params[i]) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_encoder_thread.\n")); + } + } + + /* Create video scaler threads */ + for (i=0; iaudio_data_conf.filename, "") != 0) { + /* Create audio encoder threads */ + for (i = 0; i < gf_list_count(in_data->audio_lst); i++) { + aencoder_th_params[i].in_data = in_data; + aencoder_th_params[i].audio_conf_idx = i; + aencoder_th_params[i].audio_input_data = &audio_input_data; + + aencoder_th_params[i].mq = &mq; + aencoder_th_params[i].delete_seg_mq = &delete_seg_mq; + aencoder_th_params[i].send_seg_mq = &send_frag_mq; + + if (gf_th_run(aencoder_th_params[i].thread, audio_encoder_thread, (void *) &aencoder_th_params[i]) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_encoder_thread.\n")); + } + } + } + + if (strcmp(in_data->video_data_conf.filename, "") != 0) { + /* Create video decoder thread */ + vdecoder_th_params.in_data = in_data; + vdecoder_th_params.video_input_data = &video_input_data; + vdecoder_th_params.video_input_file = video_input_file; + if (gf_th_run(vdecoder_th_params.thread, video_decoder_thread, (void *) &vdecoder_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_decoder_thread.\n")); + } + } + + if (strcmp(in_data->audio_data_conf.filename, "") != 0) { + /* Create audio decoder thread */ + adecoder_th_params.in_data = in_data; + adecoder_th_params.audio_input_data = &audio_input_data; + adecoder_th_params.audio_input_file = &audio_input_file; + if (gf_th_run(adecoder_th_params.thread, audio_decoder_thread, (void *) &adecoder_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_decoder_thread.\n")); + } + } + + if (in_data->time_shift != -1) { + /* Initialize delete segment thread */ + delete_seg_th_params.thread = gf_th_new("delete_seg_thread"); + delete_seg_th_params.in_data = in_data; + delete_seg_th_params.mq = &delete_seg_mq; + if (gf_th_run(delete_seg_th_params.thread, delete_seg_thread, (void *) &delete_seg_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for delete_seg_thread.\n")); + } + } + + if (in_data->send_message == 1) { + /* Initialize delete segment thread */ + send_frag_th_params.thread = gf_th_new("send_frag_event_thread"); + send_frag_th_params.in_data = in_data; + send_frag_th_params.mq = &send_frag_mq; + if (gf_th_run(send_frag_th_params.thread, send_frag_event, (void *) &send_frag_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for send_frag_event_thread.\n")); + } + } + +#ifndef FRAGMENTER + if (strcmp(in_data->mpd_filename, "") != 0) { + /* Initialize keyboard controller thread */ + fragmenter_th_params.thread = gf_th_new("fragmenter_thread"); + fragmenter_th_params.in_data = in_data; + fragmenter_th_params.mq = &mq; + if (gf_th_run(fragmenter_th_params.thread, fragmenter_thread, (void *) &fragmenter_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for fragmenter_thread.\n")); + } + } +#endif + +#ifndef DASHER + if (in_data->live && strcmp(in_data->mpd_filename, "") != 0) { + /* Initialize keyboard controller thread */ + dasher_th_params.thread = gf_th_new("dasher_thread"); + dasher_th_params.in_data = in_data; + if (gf_th_run(dasher_th_params.thread, dasher_thread, (void *) &dasher_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for dasher_thread.\n")); + } + } +#endif + + fprintf(stdout, "Press q or Q to exit...\n"); + + if (strcmp(in_data->audio_data_conf.filename, "") != 0) { + /* Wait for and destroy audio decoder threads */ + gf_th_stop(adecoder_th_params.thread); + gf_th_del(adecoder_th_params.thread); + } + + if (strcmp(in_data->video_data_conf.filename, "") != 0) { + /* Wait for and destroy video decoder threads */ + gf_th_stop(vdecoder_th_params.thread); + gf_th_del(vdecoder_th_params.thread); + } + + if (strcmp(in_data->audio_data_conf.filename, "") != 0) { + /* Wait for and destroy audio encoder threads */ + for (i = 0; i < gf_list_count(in_data->audio_lst); i++) { + gf_th_stop(aencoder_th_params[i].thread); + gf_th_del(aencoder_th_params[i].thread); + } + } + + if (strcmp(in_data->video_data_conf.filename, "") != 0) { + /* Wait for and destroy video encoder threads */ + for (i=0; ivideo_lst); i++) { + gf_th_stop(vencoder_th_params[i].thread); + gf_th_del(vencoder_th_params[i].thread); + } + + /* Wait for and destroy video scaler threads */ + for (i=0; ilive && strcmp(in_data->mpd_filename, "") != 0) { + /* Wait for and destroy dasher thread */ + gf_th_stop(dasher_th_params.thread); + gf_th_del(dasher_th_params.thread); + } +#endif + + keyboard_th_params.in_data->exit_signal = 1; + +#ifndef FRAGMENTER + dc_message_queue_flush(&mq); + + if (strcmp(in_data->mpd_filename, "") != 0) { + /* Wait for and destroy dasher thread */ + gf_th_stop(fragmenter_th_params.thread); + gf_th_del(fragmenter_th_params.thread); + } +#endif + + /********** Keyboard thread ***********/ + + /* Wait for and destroy keyboard controler thread */ + gf_th_stop(keyboard_th_params.thread); + gf_th_del(keyboard_th_params.thread); + + /**************************************/ + + /********** MPD generator thread ***********/ + + /* Wait for and destroy MPD generator thread */ + gf_th_stop(mpd_th_params.thread); + gf_th_del(mpd_th_params.thread); + + /**************************************/ + + if (in_data->time_shift != -1) { + // dc_message_queue_flush(&delete_seg_mq); + /* Wait for and destroy delete segment thread */ + gf_th_stop(delete_seg_th_params.thread); + gf_th_del(delete_seg_th_params.thread); + } + + if (in_data->send_message == 1) { + /* Wait for and destroy delete segment thread */ + gf_th_stop(send_frag_th_params.thread); + gf_th_del(send_frag_th_params.thread); + } + +#ifndef DASHER + if (!in_data->live && strcmp(in_data->mpd_filename, "") != 0) { + dasher_th_params.in_data = in_data; + dasher_thread((void*) &dasher_th_params); + } +#endif + +exit: + if (strcmp(in_data->audio_data_conf.filename, "") != 0) { + /* Destroy audio input data */ + dc_audio_input_data_destroy(&audio_input_data); + /* Close input audio */ + dc_audio_decoder_close(&audio_input_file); + } + + if (strcmp(in_data->video_data_conf.filename, "") != 0) { + /* Destroy video input data */ + dc_video_input_data_destroy(&video_input_data); + + for (i = 0; i < gf_list_count(in_data->vsrc); i++) { + /* Close input video */ + dc_video_decoder_close(video_input_file[i]); + } + + for (i=0; i +#include +#include + +#include "register.h" +#include "video_decoder.h" +#include "video_encoder.h" +#include "audio_decoder.h" +#include "audio_encoder.h" +#include "cmd_data.h" +#include "message_queue.h" + + +/* General thread parameters */ +typedef struct { + /* command data */ + CmdData *in_data; + /* handle to thread */ + GF_Thread *thread; + + MessageQueue *mq; +} ThreadParam; + +/* Video thread parameters */ +typedef struct { + /* command data */ + CmdData *in_data; + /* The index in the configuration file to a video entry corresponding to the thread. */ + int video_conf_idx; + /* Video input data structure corresponding to the thread. (This data is shared between video decoder and video scaler) */ + VideoInputData *video_input_data; + /* Video scaled data structure corresponding to the thread. (This data is shared between video scaler and video encoder) */ + VideoScaledData *video_scaled_data; + /* Video input file structure corresponding to the thread */ + VideoInputFile **video_input_file; + /* handle to the thread */ + GF_Thread *thread; + + MessageQueue *mq; + MessageQueue *delete_seg_mq; + MessageQueue *send_seg_mq; +} VideoThreadParam; + +/* Audio thread parameters */ +typedef struct { + /* command data */ + CmdData *in_data; + /* The index in the configuration file to an audio entry corresponding to the thread */ + int audio_conf_idx; + /* Audio input data (This data is shared between audio decoder and audio encoder */ + AudioInputData *audio_input_data; + /* Audio input file structure */ + AudioInputFile *audio_input_file; + /* handle to the thread */ + GF_Thread *thread; + + MessageQueue *mq; + MessageQueue *delete_seg_mq; + MessageQueue *send_seg_mq; +} AudioThreadParam; + +/* + * Run controler runs all decoder, scalers, and encoders + * of audio and video + * + * @param cmd_data [in] command data + * + * @return 0 on success, -1 on failure + */ +int dc_run_controler(CmdData *); + +#endif /* CONTROLER_H_ */ diff --git a/applications/dashcast/dashcast.c b/applications/dashcast/dashcast.c new file mode 100644 index 0000000..7a56315 --- /dev/null +++ b/applications/dashcast/dashcast.c @@ -0,0 +1,64 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "cmd_data.h" +#include "controler.h" + + +int main(int argc, char **argv) +{ +#ifdef GPAC_MEMORY_TRACKING + Bool use_mem_track = 0; +#endif + s32 res; + CmdData cmd_data; + + /* Read command line (performs init) and parse input */ + res = dc_parse_command(argc, argv, &cmd_data); + if (res < 0) { + if (res==-1) dc_cmd_data_destroy(&cmd_data); + return -1; + } + + res = dc_run_controler(&cmd_data); + +#ifdef GPAC_MEMORY_TRACKING + use_mem_track = cmd_data.use_mem_track; +#endif + + /* Destroy command data */ + dc_cmd_data_destroy(&cmd_data); + + if (res) return res; + +#ifdef GPAC_MEMORY_TRACKING + if (use_mem_track && (gf_memory_size() || gf_file_handles_count() )) { + gf_memory_print(); + return 2; + } +#endif + return 0; +} + diff --git a/applications/dashcast/libav_compat.h b/applications/dashcast/libav_compat.h new file mode 100644 index 0000000..9d8cb57 --- /dev/null +++ b/applications/dashcast/libav_compat.h @@ -0,0 +1,56 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Romain Bouqueau + * Copyright (c) Telecom ParisTech 2000-2013 - Romain Bouqueau 2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LIBAV_COMPAT_H_ +#define LIBAV_COMPAT_H_ + +#ifndef URL_WRONLY +#define URL_WRONLY AVIO_FLAG_WRITE +#endif + +#if (LIBAVCODEC_VERSION_MAJOR>54) +#define CODEC_ID_RAWVIDEO AV_CODEC_ID_RAWVIDEO +#define CODEC_ID_H264 AV_CODEC_ID_H264 +#endif + +#if (LIBAVCODEC_VERSION_MAJOR<54) +#define LIBAV_ENCODE_OLD +#endif + +#ifndef AV_CH_LAYOUT_STEREO +#define AV_CH_FRONT_LEFT 0x00000001 +#define AV_CH_FRONT_RIGHT 0x00000002 +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#endif + +#if (LIBAVCODEC_VERSION_MAJOR<55) || ((LIBAVCODEC_VERSION_MAJOR==55) && (LIBAVCODEC_VERSION_MINOR<=40)) +#define FF_ALLOC_FRAME avcodec_alloc_frame +#define LIBAV_FRAME_OLD +#else +#define FF_ALLOC_FRAME av_frame_alloc +#endif + +#endif + diff --git a/applications/dashcast/message_queue.c b/applications/dashcast/message_queue.c new file mode 100644 index 0000000..6f6cb68 --- /dev/null +++ b/applications/dashcast/message_queue.c @@ -0,0 +1,120 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "message_queue.h" + + +void dc_message_queue_init(MessageQueue *mq) +{ + memset(mq, 0, sizeof(MessageQueue)); + mq->first_node = NULL; + mq->last_node = NULL; + mq->nb_nodes = 0; + mq->mutex = gf_mx_new("MessageQueue Mutex"); + mq->sem = gf_sema_new(1000, 0); //TODO: why 1000 (at other places too) +} + +void dc_message_queue_put(MessageQueue *mq, void *data, u32 size) +{ + MessageQueueNode *mqn = gf_malloc(sizeof(MessageQueueNode)); + mqn->data = gf_malloc(size); + memcpy(mqn->data, data, size); + mqn->size = size; + mqn->next = NULL; + + gf_mx_p(mq->mutex); + + if (!mq->last_node) + mq->first_node = mqn; + else + mq->last_node->next = mqn; + + mq->last_node = mqn; + mq->nb_nodes++; + + gf_sema_notify(mq->sem, 1); + gf_mx_v(mq->mutex); +} + +int dc_message_queue_get(MessageQueue *mq, void * data) +{ + int ret = 0; + MessageQueueNode *mqn; + + gf_mx_p(mq->mutex); + + mqn = mq->first_node; + if (!mqn) { + gf_mx_v(mq->mutex); + ret = gf_sema_wait_for(mq->sem, 10000); + gf_mx_p(mq->mutex); + + mqn = mq->first_node; + + if (!ret || !mqn) { + gf_mx_v(mq->mutex); + return -1; + } + } + if (mqn) { + mq->first_node = mqn->next; + if (!mq->first_node) + mq->last_node = NULL; + mq->nb_nodes--; + memcpy(data, mqn->data, mqn->size); + ret = (int)mqn->size; + gf_free(mqn->data); + gf_free(mqn); + } + + gf_mx_v(mq->mutex); + + return ret; +} + +void dc_message_queue_flush(MessageQueue *mq) +{ + MessageQueueNode *mqn, *mqn1; + + gf_mx_p(mq->mutex); + + for (mqn = mq->first_node; mqn != NULL; mqn = mqn1) { + mqn1 = mqn->next; + gf_free(mqn); + } + mq->last_node = NULL; + mq->first_node = NULL; + mq->nb_nodes = 0; + + gf_sema_notify(mq->sem, 1); + gf_mx_v(mq->mutex); +} + +void dc_message_queue_free(MessageQueue *mq) +{ + dc_message_queue_flush(mq); + gf_mx_del(mq->mutex); + gf_sema_del(mq->sem); +} diff --git a/applications/dashcast/message_queue.h b/applications/dashcast/message_queue.h new file mode 100644 index 0000000..7e402c1 --- /dev/null +++ b/applications/dashcast/message_queue.h @@ -0,0 +1,58 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef MESSAGE_QUEUE_H_ +#define MESSAGE_QUEUE_H_ + +#include +#include +#include + + +typedef struct MessageQueueNode { + void *data; + u32 size; + struct MessageQueueNode *next; +} MessageQueueNode; + +typedef struct MessageQueue { + MessageQueueNode *last_node; + MessageQueueNode *first_node; + int nb_nodes; + GF_Semaphore *sem; + GF_Mutex *mutex; +} MessageQueue; + +void dc_message_queue_init(MessageQueue *mq); + +void dc_message_queue_put(MessageQueue *mq, void *data, u32 size); + +int dc_message_queue_get(MessageQueue *mq, void *data); + +void dc_message_queue_flush(MessageQueue *mq); + +void dc_message_queue_free(MessageQueue *mq); + +#endif /* MESSAGE_QUEUE_H_ */ diff --git a/applications/dashcast/register.c b/applications/dashcast/register.c new file mode 100644 index 0000000..b62bb3f --- /dev/null +++ b/applications/dashcast/register.c @@ -0,0 +1,85 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "register.h" + + +static GF_List *av_mutex = NULL; + +int lock_call_back(void ** mutex, enum AVLockOp op) +{ + switch (op) { + case AV_LOCK_CREATE: + { + static int i = 0; + char mxName[64]; + snprintf(mxName, 64, "AVLIB callback mutex %d", i++); + *mutex = gf_mx_new(mxName); + gf_list_add(av_mutex, *mutex); + break; + } + case AV_LOCK_OBTAIN: + gf_mx_p(*mutex); + break; + case AV_LOCK_RELEASE: + gf_mx_v(*mutex); + break; + case AV_LOCK_DESTROY: + gf_list_del_item(av_mutex, *mutex); + gf_mx_del(*mutex); + *mutex = NULL; + break; + } + + return 0; +} + +void dc_register_libav() +{ + av_mutex = gf_list_new(); + + av_register_all(); + avcodec_register_all(); + avdevice_register_all(); + avformat_network_init(); + + av_lockmgr_register(&lock_call_back); +} + +void dc_unregister_libav() +{ + av_lockmgr_register(NULL); + + if (av_mutex) { + while (gf_list_count(av_mutex)) { + GF_Mutex *mx = gf_list_last(av_mutex); + gf_list_rem_last(av_mutex); + gf_mx_del(mx); + } + gf_list_del(av_mutex); + av_mutex = NULL; + } +} + diff --git a/applications/dashcast/register.h b/applications/dashcast/register.h new file mode 100644 index 0000000..cbf3e32 --- /dev/null +++ b/applications/dashcast/register.h @@ -0,0 +1,50 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef REGISTER_H_ +#define REGISTER_H_ + +//#include +#include "../../modules/ffmpeg_in/ffmpeg_in.h" +#include "libavcodec/avcodec.h" +#include "libavdevice/avdevice.h" +#include "libavformat/avformat.h" + +#include + + +/* + * Register all codecs and define + * the lock manager on top of avlib + */ +void dc_register_libav(); +void dc_unregister_libav(); + +/* + * performs libav* cleanup + */ +void dc_unregister_libav(); + +#endif /* REGISTER_H_ */ diff --git a/applications/dashcast/task.c b/applications/dashcast/task.c new file mode 100644 index 0000000..d21d30f --- /dev/null +++ b/applications/dashcast/task.c @@ -0,0 +1,69 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "task.h" + + +void dc_task_init(TaskList *list) +{ + list->tasks = gf_list_new(); + list->size = 0; +} + +void dc_task_destroy(TaskList *list) +{ + gf_list_del(list->tasks); +} + +void dc_task_add(TaskList *list, int source_number, char *id_name, time_t start, time_t end) +{ + Task *task = gf_malloc(sizeof(Task)); + task->source_number = source_number; + strncpy(task->id, id_name, MAX_ID_SIZE-1); + task->start_time_t = start; + task->end_time_t = end; + gf_list_add(list->tasks, task); + list->size++; +} + +int dc_task_get_current(TaskList *list, Task *task) +{ + u32 i; + time_t now_time = time(NULL); + for (i = 0; isize; i++) { + Task *cur_task = gf_list_get(list->tasks, i); + if (now_time > cur_task->start_time_t && now_time < cur_task->end_time_t) { + //strncpy(task->id, cur_task->id, MAX_ID_SIZE-1); + //memcpy(&task->start_time, &cur_task->start_time, sizeof(struct tm)); + //memcpy(&task->end_time, &cur_task->end_time, sizeof(struct tm)); + task->source_number = cur_task->source_number; + return 0; + } + } + + task->source_number = 0; + return -1; +} + diff --git a/applications/dashcast/task.h b/applications/dashcast/task.h new file mode 100644 index 0000000..8e4ed30 --- /dev/null +++ b/applications/dashcast/task.h @@ -0,0 +1,69 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef TASK_H_ +#define TASK_H_ + +#define MAX_ID_SIZE 512 + +#include +#include +#include + + +typedef struct { + char id[MAX_ID_SIZE]; + int source_number; + time_t start_time_t; + time_t end_time_t; +} Task; + +typedef struct { + GF_List *tasks; + u32 size; +} TaskList; + +/** + * initialize a list of task + */ +void dc_task_init(TaskList *list); + +/** + * destroy the list of task + */ +void dc_task_destroy(TaskList *list); + +/** + * audio_input_data a task to the list + */ +void dc_task_add(TaskList *list, int source_number, char *id_name, time_t start, time_t end); + +/** + * give the task which corresponds to the time=NOW + * note: in the case of infering tasks, the first one is picked + */ +int dc_task_get_current(TaskList *list, Task *task); + +#endif /* TASK_H_ */ diff --git a/applications/dashcast/video_data.c b/applications/dashcast/video_data.c new file mode 100644 index 0000000..f960d57 --- /dev/null +++ b/applications/dashcast/video_data.c @@ -0,0 +1,93 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "video_data.h" + + +void dc_video_data_set_default(VideoDataConf *video_data_conf) +{ + memset(video_data_conf, 0, sizeof(VideoDataConf)); + video_data_conf->bitrate = -1; + video_data_conf->framerate = -1; + video_data_conf->crop_x = 0; + video_data_conf->crop_y = 0; + video_data_conf->height = -1; + video_data_conf->width = -1; +} + +void dc_video_input_data_end_signal(VideoInputData *video_input_data) +{ + dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf); + dc_producer_end_signal_previous(&video_input_data->producer, &video_input_data->circular_buf); +} + +int dc_video_input_data_init(VideoInputData *video_input_data, /*int width, int height, int pix_fmt*/ int num_consumers, int mode, int max_source, int video_cb_size) +{ + int i; + + dc_producer_init(&video_input_data->producer, video_cb_size, "video decoder"); + + //video_input_data->width = width; + //video_input_data->height = height; + //video_input_data->pix_fmt = pix_fmt; + + video_input_data->vprop = gf_malloc(max_source * sizeof(VideoInputProp)); + + dc_circular_buffer_create(&video_input_data->circular_buf, video_cb_size, mode, num_consumers); + + for (i=0; icircular_buf.list[i].data = (void *) video_data_node; + video_data_node->vframe = FF_ALLOC_FRAME(); + } + + return 0; +} + +void dc_video_input_data_set_prop(VideoInputData *video_input_data, int index, int width, int height, int crop_x, int crop_y, int pix_fmt, AVRational sar) +{ + video_input_data->vprop[index].width = width; + video_input_data->vprop[index].height = height; + video_input_data->vprop[index].crop_x = crop_x; + video_input_data->vprop[index].crop_y = crop_y; + video_input_data->vprop[index].pix_fmt = pix_fmt; + video_input_data->vprop[index].sar = sar; +} + +void dc_video_input_data_destroy(VideoInputData *video_input_data) +{ + int i; + for (i=0; i<(int) video_input_data->circular_buf.size; i++) { + if (video_input_data->circular_buf.list) { + VideoDataNode *video_data_node = video_input_data->circular_buf.list[i].data; + av_free(video_data_node->vframe); + gf_free(video_data_node); + } + } + + dc_circular_buffer_destroy(&video_input_data->circular_buf); + gf_free(video_input_data->vprop); +} diff --git a/applications/dashcast/video_data.h b/applications/dashcast/video_data.h new file mode 100644 index 0000000..c5bc68f --- /dev/null +++ b/applications/dashcast/video_data.h @@ -0,0 +1,169 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef VIDEO_DATA_H_ +#define VIDEO_DATA_H_ + +#include "../../modules/ffmpeg_in/ffmpeg_in.h" +#include "libavcodec/avcodec.h" +#include "libswscale/swscale.h" +#include "libav_compat.h" + +#include "circular_buffer.h" + +#include + +//anything different is broken in dash cast (random frame inversions at encoding time ...) +#define VIDEO_CB_DEFAULT_SIZE 1 + + +/* + * This structure corresponds to an + * entry of video configuration in the + * configuration file. + */ +typedef struct { + /* video file name */ + char filename[GF_MAX_PATH]; + /* video format */ + char format[GF_MAX_PATH]; + /* video format */ + char pixel_format[GF_MAX_PATH]; + /* v4l2 format */ + char v4l2f[GF_MAX_PATH]; + /* left crop */ + int crop_x; + /* top crop */ + int crop_y; + /* video final width */ + int width; + /* video final height */ + int height; + /* video bitrate */ + int bitrate; + /* video frame rate */ + int framerate; + /* video codec */ + char codec[GF_MAX_PATH]; + /* RFC6381 codec name, only valid when VIDEO_MUXER == GPAC_INIT_VIDEO_MUXER_AVC1 */ + char codec6381[GF_MAX_PATH]; + /* custom parameter to be passed directly to the encoder - free it once you're done */ + char custom[GF_MAX_PATH]; + /*low delay is used*/ + int low_delay; + + /* used for source switching */ + char source_id[GF_MAX_PATH]; + time_t start_time; + time_t end_time; + + //copy over from source file + AVRational time_base; + u64 frame_duration; +} VideoDataConf; + +typedef struct { + /* Width, height and pixel format of the input video. */ + int width; + int height; + int crop_x, crop_y; + int pix_fmt; + AVRational sar; +} VideoInputProp; + +/* + * VideoInputData is designed to keep the data + * of input video in a circular buffer. + * The circular buffer has its own mechanism for synchronization. + */ +typedef struct { + /* The circular buffer of the video frames after decoding. */ + CircularBuffer circular_buf; + /* The user of circular buffer has an index to it, which is in this variable. */ + Producer producer; + + VideoInputProp *vprop; + + /* Width, height and pixel format of the input video */ + //int width; + //int height; + //int pix_fmt; + u64 frame_duration; +} VideoInputData; + + +/* + * Each node in a circular buffer is a pointer. + * To use the circular buffer for video frame we must + * define the node. VideoDataNode simply contains + * an AVFrame. + */ +typedef struct { + AVFrame * vframe; + int source_number; + uint8_t nb_raw_frames_ref; + AVPacket raw_packet; +} VideoDataNode; + +void dc_video_data_set_default(VideoDataConf *video_data_conf); + +/* + * Initialize a VideoInputData. + * + * @param video_input_data [out] is the structure to be initialize. + * @param width [in] input video width + * @param height [in] input video height + * @param pixfmt [in] input video pixel format + * @param num_consumers [in] contains information on the number of users of circular buffer; + * which means the number of video encoders. + * @param live [in] indicates the system is live + * + * @return 0 on success, -1 on failure. + * + * @note Must use dc_video_data_destroy to free memory. + */ +int dc_video_input_data_init(VideoInputData *video_input_data,/* int width, int height, int pix_fmt,*/ int num_consumers, int mode, int num_producers, int video_cb_size); + +/* + * Set properties for a VideoInputData. + */ +void dc_video_input_data_set_prop(VideoInputData *video_input_data, int index, int width, int height, int crop_x, int crop_y, int pix_fmt, AVRational sar); + +/* + * Destroy a VideoInputData. + * + * @param video_input_data [in] the structure to be destroyed. + */ +void dc_video_input_data_destroy(VideoInputData *video_input_data); + +/* + * Signal to all the users of the circular buffer in the VideoInputData + * which the current node is the last node to consume. + * + * @param video_input_data [in] the structure to be signaled on. + */ +void dc_video_input_data_end_signal(VideoInputData *video_input_data); + +#endif /* VIDEO_DATA_H_ */ diff --git a/applications/dashcast/video_decoder.c b/applications/dashcast/video_decoder.c new file mode 100644 index 0000000..de708f9 --- /dev/null +++ b/applications/dashcast/video_decoder.c @@ -0,0 +1,402 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "video_decoder.h" +#include +#include + + +//#define DASHCAST_DEBUG_TIME_ + + +int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video_data_conf, int mode, int no_loop, int nb_consumers) +{ + s32 ret; + u32 i; + s32 open_res; + AVInputFormat *in_fmt = NULL; + AVDictionary *options = NULL; + AVCodecContext *codec_ctx; + AVCodec *codec; + + memset(video_input_file, 0, sizeof(VideoInputFile)); + + if (video_data_conf->width > 0 && video_data_conf->height > 0) { + char vres[16]; + snprintf(vres, sizeof(vres), "%dx%d", video_data_conf->width, video_data_conf->height); + ret = av_dict_set(&options, "video_size", vres, 0); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video size %s.\n", vres)); + return -1; + } + } + + if (video_data_conf->framerate > 0) { + char vfr[16]; + snprintf(vfr, sizeof(vfr), "%d", video_data_conf->framerate); + ret = av_dict_set(&options, "framerate", vfr, 0); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video framerate %s.\n", vfr)); + return -1; + } + } + + if (strlen(video_data_conf->pixel_format)) { + ret = av_dict_set(&options, "pixel_format", video_data_conf->pixel_format, 0); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set pixel format %s.\n", video_data_conf->pixel_format)); + return -1; + } + } + +#ifndef WIN32 + if (strcmp(video_data_conf->v4l2f, "") != 0) { + ret = av_dict_set(&options, "input_format", video_data_conf->v4l2f, 0); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set input format %s.\n", video_data_conf->v4l2f)); + return -1; + } + } +#endif + + if (video_data_conf->format && strcmp(video_data_conf->format, "") != 0) { + in_fmt = av_find_input_format(video_data_conf->format); + if (in_fmt == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", video_data_conf->format)); + return -1; + } + } + + video_input_file->av_fmt_ctx = NULL; + + /* Open video */ + open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, options ? &options : NULL); + if ( (open_res < 0) && !stricmp(video_data_conf->filename, "screen-capture-recorder") ) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Buggy screen capture input (open failed with code %d), retrying without specifying resolution\n", open_res)); + av_dict_set(&options, "video_size", NULL, 0); + open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, options ? &options : NULL); + } + + if ( (open_res < 0) && options) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error %d opening input - retrying without options\n", open_res)); + av_dict_free(&options); + open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, NULL); + } + + if (open_res < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file %s\n", video_data_conf->filename)); + return -1; + } + + /* Retrieve stream information */ + if (avformat_find_stream_info(video_input_file->av_fmt_ctx, NULL) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find stream information\n")); + return -1; + } + + av_dump_format(video_input_file->av_fmt_ctx, 0, video_data_conf->filename, 0); + + /* Find the first video stream */ + video_input_file->vstream_idx = -1; + for (i = 0; i < video_input_file->av_fmt_ctx->nb_streams; i++) { + if (video_input_file->av_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + video_input_file->vstream_idx = i; + break; + } + } + if (video_input_file->vstream_idx == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find a video stream\n")); + return -1; + } + + /* Get a pointer to the codec context for the video stream */ + codec_ctx = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->codec; + + /* Find the decoder for the video stream */ + codec = avcodec_find_decoder(codec_ctx->codec_id); + if (codec == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Codec is not supported.\n")); + if (!video_input_file->av_fmt_ctx_ref_cnt) + avformat_close_input(&video_input_file->av_fmt_ctx); + return -1; + } + + /* Open codec */ + if (avcodec_open2(codec_ctx, codec, NULL) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open codec.\n")); + if (!video_input_file->av_fmt_ctx_ref_cnt) + avformat_close_input(&video_input_file->av_fmt_ctx); + return -1; + } + + video_input_file->width = codec_ctx->width; + video_input_file->height = codec_ctx->height; + video_input_file->sar = codec_ctx->sample_aspect_ratio; + + video_input_file->pix_fmt = codec_ctx->pix_fmt; + if (codec_ctx->time_base.num==1) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("AVCTX give frame duration of %d/%d - keeping requested rate %d, but this may result in unexpected behaviour.\n", codec_ctx->time_base.num, codec_ctx->time_base.den, video_data_conf->framerate )); + + if (codec_ctx->time_base.den==1000000) { + codec_ctx->time_base.num = codec_ctx->time_base.den / video_data_conf->framerate; + } + } + else if (video_data_conf->framerate >= 0 && codec_ctx->time_base.num) { + video_data_conf->framerate = codec_ctx->time_base.den / codec_ctx->time_base.num; + } + if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { + const int num = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.num; + const int den = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.den == 0 ? 1 : video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.den; + video_data_conf->framerate = num / den; + if (video_data_conf->framerate / 1000 != 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Framerate %d was divided by 1000: %d\n", video_data_conf->framerate, video_data_conf->framerate/1000)); + video_data_conf->framerate = video_data_conf->framerate / 1000; + } + + if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { + video_data_conf->framerate = num / den; + if (video_data_conf->framerate / 1000 != 0) { + video_data_conf->framerate = video_data_conf->framerate / 1000; + } + } + } + + if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Invalid input framerate %d (AVCTX timebase is %d/%d).\n", video_data_conf->framerate, codec_ctx->time_base.num, codec_ctx->time_base.den)); + return -1; + } + + video_data_conf->time_base = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->time_base; + video_input_file->mode = mode; + video_input_file->no_loop = no_loop; + video_input_file->nb_consumers = nb_consumers; + return 0; +} + +int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *video_input_data, int source_number, int use_source_timing, int is_live_capture, const int *exit_signal_addr) +{ +#ifdef DASHCAST_DEBUG_TIME_ + struct timeval start, end; + long elapsed_time; +#endif + AVPacket packet; + int ret, got_frame, already_locked = 0; + AVCodecContext *codec_ctx; + VideoDataNode *video_data_node; + + /* Get a pointer to the codec context for the video stream */ + codec_ctx = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->codec; + + /* Read frames */ + while (1) { +#ifdef DASHCAST_DEBUG_TIME_ + gf_gettimeofday(&start, NULL); +#endif + memset(&packet, 0, sizeof(AVPacket)); + ret = av_read_frame(video_input_file->av_fmt_ctx, &packet); +#ifdef DASHCAST_DEBUG_TIME_ + gf_gettimeofday(&end, NULL); + elapsed_time = (end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec); + fprintf(stdout, "fps: %f\n", 1000000.0/elapsed_time); +#endif + + /* If we demux for the audio thread, send the packet to the audio */ + if (video_input_file->av_fmt_ctx_ref_cnt && ((packet.stream_index != video_input_file->vstream_idx) || (ret == AVERROR_EOF))) { + AVPacket *packet_copy = NULL; + if (ret != AVERROR_EOF) { + GF_SAFEALLOC(packet_copy, AVPacket); + memcpy(packet_copy, &packet, sizeof(AVPacket)); + } + + assert(video_input_file->av_pkt_list); + gf_mx_p(video_input_file->av_pkt_list_mutex); + gf_list_add(video_input_file->av_pkt_list, packet_copy); + gf_mx_v(video_input_file->av_pkt_list_mutex); + + if (ret != AVERROR_EOF) { + continue; + } + } + + if (ret == AVERROR_EOF) { + if (video_input_file->mode == LIVE_MEDIA && video_input_file->no_loop == 0) { + av_seek_frame(video_input_file->av_fmt_ctx, video_input_file->vstream_idx, 0, 0); + av_free_packet(&packet); + continue; + } + + dc_producer_lock(&video_input_data->producer, &video_input_data->circular_buf); + dc_producer_unlock_previous(&video_input_data->producer, &video_input_data->circular_buf); + video_data_node = (VideoDataNode *) dc_producer_produce(&video_input_data->producer, &video_input_data->circular_buf); + video_data_node->source_number = source_number; + /* Flush decoder */ + memset(&packet, 0, sizeof(AVPacket)); +#ifndef FF_API_AVFRAME_LAVC + avcodec_get_frame_defaults(video_data_node->vframe); +#else + av_frame_unref(video_data_node->vframe); +#endif + + avcodec_decode_video2(codec_ctx, video_data_node->vframe, &got_frame, &packet); + if (got_frame) { + dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); + return 0; + } + + dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf); + dc_producer_unlock(&video_input_data->producer, &video_input_data->circular_buf); + return -2; + } + else if (ret < 0) + { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot read video frame.\n")); + continue; + } + + /* Is this a packet from the video stream? */ + if (packet.stream_index == video_input_file->vstream_idx) { + if (!already_locked) { + if (dc_producer_lock(&video_input_data->producer, &video_input_data->circular_buf) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped a video frame\n")); + continue; + } + + dc_producer_unlock_previous(&video_input_data->producer, &video_input_data->circular_buf); + + already_locked = 1; + } + + video_data_node = (VideoDataNode *) dc_producer_produce(&video_input_data->producer, &video_input_data->circular_buf); + video_data_node->source_number = source_number; + + /* Set video frame to default */ +#ifndef FF_API_AVFRAME_LAVC + avcodec_get_frame_defaults(video_data_node->vframe); +#else + av_frame_unref(video_data_node->vframe); +#endif + + /* Decode video frame */ + if (avcodec_decode_video2(codec_ctx, video_data_node->vframe, &got_frame, &packet) < 0) { + av_free_packet(&packet); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while decoding video.\n")); + dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf); + dc_producer_unlock(&video_input_data->producer, &video_input_data->circular_buf); + return -1; + } + + /* Did we get a video frame? */ + if (got_frame) { + if (use_source_timing && is_live_capture) { + u64 pts; + if (video_input_file->pts_init == 0) { + video_input_file->pts_init = 1; + video_input_file->utc_at_init = gf_net_get_utc(); + video_input_file->first_pts = packet.pts; + video_input_file->prev_pts = 0; + video_input_data->frame_duration = codec_ctx->time_base.num; + + video_input_file->sync_tolerance = 9*video_input_data->frame_duration/5; + //TODO - check with audio if sync is OK + } + + //move to 0-based PTS + pts = packet.pts - video_input_file->first_pts; + + if (video_input_file->prev_pts + video_input_data->frame_duration / 2 > pts) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DashCast] Error in PTS , diff too small (previous "LLU" - current "LLU"\n", video_input_file->prev_pts, pts)); + } + + + //check for drop frames +#ifndef GPAC_DISABLE_LOG + if (0 && gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_WARNING)) { + if (pts - video_input_file->prev_pts > video_input_file->sync_tolerance) { + u32 nb_lost=0; + while (video_input_file->prev_pts + video_input_data->frame_duration + video_input_file->sync_tolerance < pts) { + video_input_file->prev_pts += video_input_data->frame_duration; + nb_lost++; + } + if (nb_lost) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DashCast] Capture lost %d video frames \n", nb_lost)); + } + } + } +#endif + + video_input_file->prev_pts = pts; + video_data_node->vframe->pts = pts; + } + + if (video_data_node->vframe->pts==AV_NOPTS_VALUE) { + if (!use_source_timing) { + video_data_node->vframe->pts = video_input_file->frame_decoded; + } else { + video_data_node->vframe->pts = video_data_node->vframe->pkt_pts; + } + } + video_input_file->frame_decoded++; + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video Frame TS "LLU" decoded at UTC "LLU" ms\n", video_data_node->vframe->pts, gf_net_get_utc() )); + + // For a decode/encode process we must free this memory. + //But if the input is raw and there is no need to decode then + // the packet is directly passed for decoded frame. We must wait until rescale is done before freeing it + + if (codec_ctx->codec->id == CODEC_ID_RAWVIDEO) { + video_data_node->nb_raw_frames_ref = video_input_file->nb_consumers; + + video_data_node->raw_packet = packet; + + dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); + while (video_data_node->nb_raw_frames_ref && ! *exit_signal_addr) { + gf_sleep(0); + } + } else { + dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); + av_free_packet(&packet); + } + return 0; + + } + } + + /* Free the packet that was allocated by av_read_frame */ + av_free_packet(&packet); + } + + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown error while reading video frame.\n")); + return -1; +} + +void dc_video_decoder_close(VideoInputFile *video_input_file) +{ + /* Close the video format context */ + if (!video_input_file->av_fmt_ctx_ref_cnt) + avformat_close_input(&video_input_file->av_fmt_ctx); + + video_input_file->av_pkt_list = NULL; + video_input_file->av_pkt_list_mutex = NULL; +} diff --git a/applications/dashcast/video_decoder.h b/applications/dashcast/video_decoder.h new file mode 100644 index 0000000..59a6f94 --- /dev/null +++ b/applications/dashcast/video_decoder.h @@ -0,0 +1,97 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef VIDEO_DECODER_H_ +#define VIDEO_DECODER_H_ + +#include "video_data.h" + +#include "libavformat/avformat.h" +#include "libavdevice/avdevice.h" + + +/* + * The structure which keeps the data of + * input video file. + */ +typedef struct { + /* Format context structure provided by avlib to open and read from a media file. */ + AVFormatContext *av_fmt_ctx; + /* A reference counter on the format context (may be shared with other sources). Currently redundant with av_pkt_list non-NULLness. */ + int av_fmt_ctx_ref_cnt; + /* A list of AVPackets and return value to be processed: when this parameter is non-null, + * the video thread makes the demux and pushes the packets. Packets must be freed when retrieved.*/ + GF_List *av_pkt_list; + GF_Mutex *av_pkt_list_mutex; + /* The index of the video stream in the file. */ + int vstream_idx; + /* video width, height, and pixel format. */ + int width; + int height; + int pix_fmt; + AVRational sar; + + int mode; + int no_loop, nb_consumers; + + u32 frame_decoded; + Bool pts_init; + u64 first_pts, prev_pts, sync_tolerance; + u64 utc_at_init; +} VideoInputFile; + +/* + * Open the input video + * + * @param cmd_data [in] contains information about the file name + * and the video format. + * + * @param video_input_file [out] pointer to the structure which we want to + * open the file + * + * @return 0 on success -1 on failure. + */ +int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video_data_conf, int mode, int no_loop, int nb_consumers); + +/* + * Read and decode video and put decoded frames on circular buffer + * + * @param video_input_file [in] contains info on input video. + * @param video_input_data [out] the decoded samples will be put + * on the circular buffer of this parameter. + * + * @return 0 on success, -1 on failure, -2 on EOF (end of the file) + */ +int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *video_input_data, int source_number, int use_source_timing, int is_live_capture, const int *exit_signal_addr); + +/* + * Close the input video + * + * @param video_input_file [in] the video file to be closed + * + */ +void dc_video_decoder_close(VideoInputFile *); + +#endif /* VIDEO_DECODER_H_ */ diff --git a/applications/dashcast/video_encoder.c b/applications/dashcast/video_encoder.c new file mode 100644 index 0000000..1b07cf1 --- /dev/null +++ b/applications/dashcast/video_encoder.c @@ -0,0 +1,290 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "video_encoder.h" +#include "libavutil/opt.h" +#include "libavdevice/avdevice.h" + + +#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__) + +#define _TOSTR(_val) #_val +#define TOSTR(_val) _TOSTR(_val) + +#endif + + +//#define DEBUG 1 + + +/** + * A function which pushes argument to a libav codec using its private data. + * param priv_data + * param options a list of space separated and ':' affected options (e.g. "a:b c:d e:f"). @options be non NULL. + */ +void build_dict(void *priv_data, const char *options) { + char *opt = gf_strdup(options); + char *tok = strtok(opt, "="); + char *tokval = NULL; + while (tok && (tokval=strtok(NULL, " "))) { + if (av_opt_set(priv_data, tok, tokval, 0) < 0) + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown custom option \"%s\" with value \"%s\" in %s\n", tok, tokval, options)); + tok = strtok(NULL, "="); + } + gf_free(opt); +} + +int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing, AVRational sar) +{ + video_output_file->vbuf_size = 9 * video_data_conf->width * video_data_conf->height + 10000; + video_output_file->vbuf = (uint8_t *) av_malloc(video_output_file->vbuf_size); + video_output_file->video_data_conf = video_data_conf; + + video_output_file->codec = avcodec_find_encoder_by_name(video_data_conf->codec); + if (video_output_file->codec == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output video codec %s not found\n", video_data_conf->codec)); + return -1; + } + + video_output_file->codec_ctx = avcodec_alloc_context3(video_output_file->codec); + + video_output_file->codec_ctx->codec_id = video_output_file->codec->id; + video_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; + video_output_file->codec_ctx->bit_rate = video_data_conf->bitrate; + video_output_file->codec_ctx->width = video_data_conf->width; + video_output_file->codec_ctx->height = video_data_conf->height; + video_output_file->codec_ctx->sample_aspect_ratio = sar; + + video_output_file->codec_ctx->time_base.num = 1; + video_output_file->codec_ctx->time_base.den = video_output_file->gop_size ? video_output_file->gop_size : video_data_conf->framerate; + + video_output_file->use_source_timing = use_source_timing; + if (use_source_timing) { + //for avcodec to do rate allocation, we need to have ctx->timebase == 1/framerate + video_output_file->codec_ctx->time_base.den = video_data_conf->time_base.den; + video_output_file->codec_ctx->time_base.num = video_data_conf->time_base.num * video_data_conf->time_base.den / video_data_conf->framerate; + } + video_output_file->codec_ctx->pix_fmt = PIX_FMT_YUV420P; + video_output_file->codec_ctx->gop_size = video_data_conf->framerate; + +// video_output_file->codec_ctx->codec_id = video_codec->id; +// video_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; +// video_output_file->codec_ctx->bit_rate = video_data_conf->bitrate; +// video_output_file->codec_ctx->width = video_data_conf->width; +// video_output_file->codec_ctx->height = video_data_conf->height; +// video_output_file->codec_ctx->time_base = (AVRational) {1 , +// video_output_file->video_data_conf->framerate}; +// video_output_file->codec_ctx->codec->pix_fmt = PIX_FMT_YUV420P; + video_output_file->codec_ctx->gop_size = video_data_conf->framerate; +// +// av_opt_set(video_output_file->codec_ctx->priv_data, "preset", "ultrafast", 0); +// av_opt_set(video_output_file->codec_ctx->priv_data, "tune", "zerolatency", 0); + + /* + video_output_file->codec_ctx->max_b_frames = 0; + video_output_file->codec_ctx->thread_count = 1; + video_output_file->codec_ctx->delay = 0; + video_output_file->codec_ctx->rc_lookahead = 0; + */ + + /* + * video_stream->codec->gosize = video_output_file->vfr; + * videoStream->codec->gosize = 1; + * video_stream->codec->rc_lookahead = 0; + * videoStream->time_base = (AVRational) {1 , 1000000}; + * videoStream->r_frame_rate = (AVRational) {outVideoCtx->video_framerate, 1}; + * av_opt_set(videoStream->codec->priv_data, "preset", "slow", 0); + * videoStream->codec->me_range = 16; + * videoStream->codec->max_qdiff = 4; + * videoStream->codec->qmin = 10; + * videoStream->codec->qmax = 51; + * videoStream->codec->qcompress = 0.6; + * videoStream->codec->profile = FF_PROFILE_H264_BASELINE; + * videoStream->codec->level = 10; + * + */ + + if ( strlen(video_data_conf->custom) ) { + build_dict(video_output_file->codec_ctx->priv_data, video_data_conf->custom); + } else if (video_data_conf->low_delay) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video Encoder: applying default options (preset=ultrafast tune=zerolatency)\n")); + av_opt_set(video_output_file->codec_ctx->priv_data, "vprofile", "baseline", 0); + av_opt_set(video_output_file->codec_ctx->priv_data, "preset", "ultrafast", 0); + av_opt_set(video_output_file->codec_ctx->priv_data, "tune", "zerolatency", 0); + if (strstr(video_data_conf->codec, "264")) { + av_opt_set(video_output_file->codec_ctx->priv_data, "x264opts", "no-mbtree:sliced-threads:sync-lookahead=0", 0); + } + } + + if (video_output_file->gdr) { + av_opt_set_int(video_output_file->codec_ctx->priv_data, "intra-refresh", 1, 0); + av_opt_set_int(video_output_file->codec_ctx->priv_data, "key-int", video_output_file->gdr, 0); + } + + //the global header gives access to the extradata (SPS/PPS) + video_output_file->codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + + video_output_file->vstream_idx = 0;//video_stream->index; + + /* open the video codec - options are passed thru video_output_file->codec_ctx->priv_data */ + if (avcodec_open2(video_output_file->codec_ctx, video_output_file->codec, NULL) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n")); + return -1; + } + + video_output_file->rep_id = video_data_conf->filename; + return 0; +} + +int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData *video_scaled_data) +{ + VideoDataNode *video_data_node; + int ret; + + AVCodecContext *video_codec_ctx = video_output_file->codec_ctx; + + //FIXME: deadlock when pressing 'q' with BigBuckBunny_640x360.m4v + ret = dc_consumer_lock(&video_output_file->consumer, &video_scaled_data->circular_buf); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video encoder got an end of buffer!\n")); + return -2; + } + + if (video_scaled_data->circular_buf.size > 1) + dc_consumer_unlock_previous(&video_output_file->consumer, &video_scaled_data->circular_buf); + + video_data_node = (VideoDataNode*)dc_consumer_consume(&video_output_file->consumer, &video_scaled_data->circular_buf); + + /* + * Set PTS (method 1) + */ + if (!video_output_file->use_source_timing) { + video_data_node->vframe->pts = video_codec_ctx->frame_number; + } + + /* Encoding video */ + { + int got_packet = 0; + AVPacket pkt; + av_init_packet(&pkt); + pkt.data = video_output_file->vbuf; + pkt.size = video_output_file->vbuf_size; + pkt.pts = pkt.dts = video_data_node->vframe->pkt_dts = video_data_node->vframe->pkt_pts = video_data_node->vframe->pts; + video_data_node->vframe->pict_type = 0; + video_data_node->vframe->width = video_codec_ctx->width; + video_data_node->vframe->height = video_codec_ctx->height; + video_data_node->vframe->format = video_codec_ctx->pix_fmt; + + +#ifdef LIBAV_ENCODE_OLD + if (!video_output_file->segment_started) + video_data_node->vframe->pict_type = FF_I_TYPE; + + video_output_file->encoded_frame_size = avcodec_encode_video(video_codec_ctx, video_output_file->vbuf, video_output_file->vbuf_size, video_data_node->vframe); + got_packet = video_output_file->encoded_frame_size>=0 ? 1 : 0; +#else + //this is correct but unfortunately doesn't work with some versions of FFMPEG (output is just grey video ...) + + if (!video_output_file->segment_started) + video_data_node->vframe->pict_type = AV_PICTURE_TYPE_I; + + video_output_file->encoded_frame_size = avcodec_encode_video2(video_codec_ctx, &pkt, video_data_node->vframe, &got_packet); +#endif + + //this is not true with libav ! +#ifndef GPAC_USE_LIBAV + if (video_output_file->encoded_frame_size >= 0) + video_output_file->encoded_frame_size = pkt.size; +#else + if (got_packet) + video_output_file->encoded_frame_size = pkt.size; +#endif + if (video_output_file->encoded_frame_size >= 0) { + if (got_packet) { + video_codec_ctx->coded_frame->pts = video_codec_ctx->coded_frame->pkt_pts = pkt.pts; + video_codec_ctx->coded_frame->pkt_dts = pkt.dts; + video_codec_ctx->coded_frame->key_frame = (pkt.flags & AV_PKT_FLAG_KEY) ? 1 : 0; + } + } + } + + dc_consumer_advance(&video_output_file->consumer); + + if (video_scaled_data->circular_buf.size == 1) + dc_consumer_unlock_previous(&video_output_file->consumer, &video_scaled_data->circular_buf); + + if (video_output_file->encoded_frame_size < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error occured while encoding video frame.\n")); + return -1; + } + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video %s Frame TS "LLU" encoded at UTC "LLU" ms\n", video_output_file->rep_id, /*video_data_node->source_number, */video_data_node->vframe->pts, gf_net_get_utc() )); + + /* if zero size, it means the image was buffered */ +// if (out_size > 0) { +// av_init_packet(&pkt); +// pkt.data = NULL; +// pkt.size = 0; +// +// if (video_codec_ctx->coded_frame->pts != AV_NOPTS_VALUE) { +// pkt.pts = av_rescale_q(video_codec_ctx->coded_frame->pts, +// video_codec_ctx->time_base, video_stream->time_base); +// } +// +// +// if (video_codec_ctx->coded_frame->key_frame) +// pkt.flags |= AV_PKT_FLAG_KEY; +// +// pkt.stream_index = video_stream->index; +// pkt.data = video_output_file->vbuf; +// pkt.size = out_size; +// +// // write the compressed frame in the media file +// if (av_interleaved_write_frame(video_output_file->av_fmt_ctx, &pkt) +// != 0) { +// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Writing frame is not successful\n")); +// return -1; +// } +// +// av_free_packet(&pkt); +// +// } + + return video_output_file->encoded_frame_size; +} + +void dc_video_encoder_close(VideoOutputFile *video_output_file) +{ +// int i; +// +// // free the streams +// for (i = 0; i < video_output_file->av_fmt_ctx->nb_streams; i++) { +// avcodec_close(video_output_file->av_fmt_ctx->streams[i]->codec); +// av_freep(&video_output_file->av_fmt_ctx->streams[i]->info); +// } + av_free(video_output_file->vbuf); + avcodec_close(video_output_file->codec_ctx); + av_free(video_output_file->codec_ctx); +} diff --git a/applications/dashcast/video_encoder.h b/applications/dashcast/video_encoder.h new file mode 100644 index 0000000..26e4cb6 --- /dev/null +++ b/applications/dashcast/video_encoder.h @@ -0,0 +1,63 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef VIDEO_ENCODER_H_ +#define VIDEO_ENCODER_H_ + +#include "video_muxer.h" + + +/* + * Open an video stream + * + * @param video_output_file [in] add a video stream to the file + * with the parameters already passed to open_video_output + * + * @return 0 on success, -1 on failure + */ +int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing, AVRational sar); + +/* + * Read the decoded video frames from circular buffer + * of the corresponding resolution + * and encode and write them on the output file + * + * @param video_output_file [in] video output file + * @param video_scaled_data [in] scaled video data structure which + * contains a circular buffer with video frames + * + * @return 0 on success, -1 on failure, -2 on finishing; + * when there is no more data on circular buffer to encode + */ +int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData *video_scaled_data); + +/* + * Close the output video file + * + * @param video_output_file [in] video output file + */ +void dc_video_encoder_close(VideoOutputFile *video_output_file); + +#endif /* VIDEO_ENCODER_H_ */ diff --git a/applications/dashcast/video_muxer.c b/applications/dashcast/video_muxer.c new file mode 100644 index 0000000..7f0ae3c --- /dev/null +++ b/applications/dashcast/video_muxer.c @@ -0,0 +1,924 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "video_muxer.h" +#include "libavutil/opt.h" +#include + + +/** + * A function which takes FFmpeg H264 extradata (SPS/PPS) and bring them ready to be pushed to the MP4 muxer. + * @param extradata + * @param extradata_size + * @param dstcfg + * @returns GF_OK is the extradata was parsed and is valid, other values otherwise. + */ +static GF_Err avc_import_ffextradata(const u8 *extradata, const u64 extradata_size, GF_AVCConfig *dstcfg) +{ +#ifdef GPAC_DISABLE_AV_PARSERS + return GF_OK; +#else + u8 nal_size; + AVCState avc; + GF_BitStream *bs; + if (!extradata || (extradata_size < sizeof(u32))) + return GF_BAD_PARAM; + bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ); + if (!bs) + return GF_BAD_PARAM; + if (gf_bs_read_u32(bs) != 0x00000001) { + gf_bs_del(bs); + return GF_BAD_PARAM; + } + + //SPS + { + s32 idx; + char *buffer = NULL; + const u64 nal_start = 4; + nal_size = gf_media_nalu_next_start_code_bs(bs); + if (nal_start + nal_size > extradata_size) { + gf_bs_del(bs); + return GF_BAD_PARAM; + } + buffer = (char*)gf_malloc(nal_size); + gf_bs_read_data(bs, buffer, nal_size); + gf_bs_seek(bs, nal_start); + if ((gf_bs_read_u8(bs) & 0x1F) != GF_AVC_NALU_SEQ_PARAM) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + idx = gf_media_avc_read_sps(buffer, nal_size, &avc, 0, NULL); + if (idx < 0) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + dstcfg->configurationVersion = 1; + dstcfg->profile_compatibility = avc.sps[idx].prof_compat; + dstcfg->AVCProfileIndication = avc.sps[idx].profile_idc; + dstcfg->AVCLevelIndication = avc.sps[idx].level_idc; + dstcfg->chroma_format = avc.sps[idx].chroma_format; + dstcfg->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8; + dstcfg->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8; + + { + GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + slc->size = nal_size; + slc->id = idx; + slc->data = buffer; + gf_list_add(dstcfg->sequenceParameterSets, slc); + } + } + + //PPS + { + s32 idx; + char *buffer = NULL; + const u64 nal_start = 4 + nal_size + 4; + gf_bs_seek(bs, nal_start); + nal_size = gf_media_nalu_next_start_code_bs(bs); + if (nal_start + nal_size > extradata_size) { + gf_bs_del(bs); + return GF_BAD_PARAM; + } + buffer = (char*)gf_malloc(nal_size); + gf_bs_read_data(bs, buffer, nal_size); + gf_bs_seek(bs, nal_start); + if ((gf_bs_read_u8(bs) & 0x1F) != GF_AVC_NALU_PIC_PARAM) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + idx = gf_media_avc_read_pps(buffer, nal_size, &avc); + if (idx < 0) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + { + GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + slc->size = nal_size; + slc->id = idx; + slc->data = buffer; + gf_list_add(dstcfg->pictureParameterSets, slc); + } + } + + gf_bs_del(bs); + return GF_OK; +#endif +} + +/** + * A function which takes FFmpeg H265 extradata (SPS/PPS) and bring them ready to be pushed to the MP4 muxer. + * @param extradata + * @param extradata_size + * @param dstcfg + * @returns GF_OK is the extradata was parsed and is valid, other values otherwise. + */ +static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_size, GF_HEVCConfig *dst_cfg) +{ +#ifdef GPAC_DISABLE_AV_PARSERS + return GF_OK; +#else + HEVCState hevc; + GF_HEVCParamArray *vpss = NULL, *spss = NULL, *ppss = NULL; + GF_BitStream *bs; + char *buffer = NULL; + u32 buffer_size = 0; + if (!extradata || (extradata_size < sizeof(u32))) + return GF_BAD_PARAM; + bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ); + if (!bs) + return GF_BAD_PARAM; + + memset(&hevc, 0, sizeof(HEVCState)); + hevc.sps_active_idx = -1; + + while (gf_bs_available(bs)) { + s32 idx; + GF_AVCConfigSlot *slc; + u8 nal_unit_type, temporal_id, layer_id; + u64 nal_start; + u32 nal_size; + + if (gf_bs_read_u32(bs) != 0x00000001) { + gf_bs_del(bs); + return GF_BAD_PARAM; + } + nal_start = gf_bs_get_position(bs); + nal_size = gf_media_nalu_next_start_code_bs(bs); + if (nal_start + nal_size > extradata_size) { + gf_bs_del(bs); + return GF_BAD_PARAM; + } + + if (nal_size > buffer_size) { + buffer = (char*)gf_realloc(buffer, nal_size); + buffer_size = nal_size; + } + gf_bs_read_data(bs, buffer, nal_size); + gf_bs_seek(bs, nal_start); + + gf_media_hevc_parse_nalu(bs, &hevc, &nal_unit_type, &temporal_id, &layer_id); + if (layer_id) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + switch (nal_unit_type) { + case GF_HEVC_NALU_VID_PARAM: + idx = gf_media_hevc_read_vps(buffer, nal_size , &hevc); + if (idx < 0) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + assert(hevc.vps[idx].state == 1); //we don't expect multiple VPS + if (hevc.vps[idx].state == 1) { + hevc.vps[idx].state = 2; + hevc.vps[idx].crc = gf_crc_32(buffer, nal_size); + + dst_cfg->avgFrameRate = hevc.vps[idx].rates[0].avg_pic_rate; + dst_cfg->constantFrameRate = hevc.vps[idx].rates[0].constand_pic_rate_idc; + dst_cfg->numTemporalLayers = hevc.vps[idx].max_sub_layers; + dst_cfg->temporalIdNested = hevc.vps[idx].temporal_id_nesting; + + if (!vpss) { + GF_SAFEALLOC(vpss, GF_HEVCParamArray); + vpss->nalus = gf_list_new(); + gf_list_add(dst_cfg->param_array, vpss); + vpss->array_completeness = 1; + vpss->type = GF_HEVC_NALU_VID_PARAM; + } + + slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + slc->size = nal_size; + slc->id = idx; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + memcpy(slc->data, buffer, sizeof(char)*slc->size); + + gf_list_add(vpss->nalus, slc); + } + break; + case GF_HEVC_NALU_SEQ_PARAM: + idx = gf_media_hevc_read_sps(buffer, nal_size, &hevc); + if (idx < 0) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + assert(!(hevc.sps[idx].state & AVC_SPS_DECLARED)); //we don't expect multiple SPS + if ((hevc.sps[idx].state & AVC_SPS_PARSED) && !(hevc.sps[idx].state & AVC_SPS_DECLARED)) { + hevc.sps[idx].state |= AVC_SPS_DECLARED; + hevc.sps[idx].crc = gf_crc_32(buffer, nal_size); + } + + dst_cfg->configurationVersion = 1; + dst_cfg->profile_space = hevc.sps[idx].ptl.profile_space; + dst_cfg->tier_flag = hevc.sps[idx].ptl.tier_flag; + dst_cfg->profile_idc = hevc.sps[idx].ptl.profile_idc; + dst_cfg->general_profile_compatibility_flags = hevc.sps[idx].ptl.profile_compatibility_flag; + dst_cfg->progressive_source_flag = hevc.sps[idx].ptl.general_progressive_source_flag; + dst_cfg->interlaced_source_flag = hevc.sps[idx].ptl.general_interlaced_source_flag; + dst_cfg->non_packed_constraint_flag = hevc.sps[idx].ptl.general_non_packed_constraint_flag; + dst_cfg->frame_only_constraint_flag = hevc.sps[idx].ptl.general_frame_only_constraint_flag; + + dst_cfg->constraint_indicator_flags = hevc.sps[idx].ptl.general_reserved_44bits; + dst_cfg->level_idc = hevc.sps[idx].ptl.level_idc; + + dst_cfg->chromaFormat = hevc.sps[idx].chroma_format_idc; + dst_cfg->luma_bit_depth = hevc.sps[idx].bit_depth_luma; + dst_cfg->chroma_bit_depth = hevc.sps[idx].bit_depth_chroma; + + if (!spss) { + GF_SAFEALLOC(spss, GF_HEVCParamArray); + spss->nalus = gf_list_new(); + gf_list_add(dst_cfg->param_array, spss); + spss->array_completeness = 1; + spss->type = GF_HEVC_NALU_SEQ_PARAM; + } + + slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + slc->size = nal_size; + slc->id = idx; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + memcpy(slc->data, buffer, sizeof(char)*slc->size); + gf_list_add(spss->nalus, slc); + break; + case GF_HEVC_NALU_PIC_PARAM: + idx = gf_media_hevc_read_pps(buffer, nal_size, &hevc); + if (idx < 0) { + gf_bs_del(bs); + gf_free(buffer); + return GF_BAD_PARAM; + } + + assert(hevc.pps[idx].state == 1); //we don't expect multiple PPS + if (hevc.pps[idx].state == 1) { + hevc.pps[idx].state = 2; + hevc.pps[idx].crc = gf_crc_32(buffer, nal_size); + + if (!ppss) { + GF_SAFEALLOC(ppss, GF_HEVCParamArray); + ppss->nalus = gf_list_new(); + gf_list_add(dst_cfg->param_array, ppss); + ppss->array_completeness = 1; + ppss->type = GF_HEVC_NALU_PIC_PARAM; + } + + slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + slc->size = nal_size; + slc->id = idx; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + memcpy(slc->data, buffer, sizeof(char)*slc->size); + + gf_list_add(ppss->nalus, slc); + } + break; + default: + break; + } + + if (gf_bs_seek(bs, nal_start+nal_size)) { + assert(nal_start+nal_size <= gf_bs_get_size(bs)); + break; + } + } + + gf_bs_del(bs); + gf_free(buffer); + + return GF_OK; +#endif +} + +#ifndef GPAC_DISABLE_ISOM + +static GF_Err dc_gpac_video_write_config(VideoOutputFile *video_output_file, u32 *di, u32 track) { + GF_Err ret; + if (video_output_file->codec_ctx->codec_id == CODEC_ID_H264) { + GF_AVCConfig *avccfg; + avccfg = gf_odf_avc_cfg_new(); + if (!avccfg) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create AVCConfig\n")); + return GF_OUT_OF_MEM; + } + + ret = avc_import_ffextradata(video_output_file->codec_ctx->extradata, video_output_file->codec_ctx->extradata_size, avccfg); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot parse AVC/H264 SPS/PPS\n")); + gf_odf_avc_cfg_del(avccfg); + return ret; + } + + ret = gf_isom_avc_config_new(video_output_file->isof, track, avccfg, NULL, NULL, di); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_avc_config_new\n", gf_error_to_string(ret))); + return ret; + } + + gf_odf_avc_cfg_del(avccfg); + + //inband SPS/PPS + if (video_output_file->muxer_type == GPAC_INIT_VIDEO_MUXER_AVC3) { + ret = gf_isom_avc_set_inband_config(video_output_file->isof, track, 1); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_avc_set_inband_config\n", gf_error_to_string(ret))); + return ret; + } + } + } else if (!strcmp(video_output_file->codec_ctx->codec->name, "libx265")) { //FIXME CODEC_ID_HEVC would break on old releases + GF_HEVCConfig *hevccfg = gf_odf_hevc_cfg_new(); + if (!hevccfg) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create HEVCConfig\n")); + return GF_OUT_OF_MEM; + } + + ret = hevc_import_ffextradata(video_output_file->codec_ctx->extradata, video_output_file->codec_ctx->extradata_size, hevccfg); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot parse HEVC/H265 SPS/PPS\n")); + gf_odf_hevc_cfg_del(hevccfg); + return ret; + } + + ret = gf_isom_hevc_config_new(video_output_file->isof, track, hevccfg, NULL, NULL, di); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_hevc_config_new\n", gf_error_to_string(ret))); + return ret; + } + + gf_odf_hevc_cfg_del(hevccfg); + + //inband SPS/PPS + if (video_output_file->muxer_type == GPAC_INIT_VIDEO_MUXER_AVC3) { + ret = gf_isom_hevc_set_inband_config(video_output_file->isof, track, 1); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_hevc_set_inband_config\n", gf_error_to_string(ret))); + return ret; + } + } + } + + return GF_OK; +} + +int dc_gpac_video_moov_create(VideoOutputFile *video_output_file, char *filename) +{ + GF_Err ret; + AVCodecContext *video_codec_ctx = video_output_file->codec_ctx; + u32 di, track; + + //TODO: For the moment it is fixed + //u32 sample_dur = video_output_file->codec_ctx->time_base.den; + + //int64_t profile = 0; + //av_opt_get_int(video_output_file->codec_ctx->priv_data, "level", AV_OPT_SEARCH_CHILDREN, &profile); + + video_output_file->isof = gf_isom_open(filename, GF_ISOM_OPEN_WRITE, NULL); + if (!video_output_file->isof) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open iso file %s\n", filename)); + return -1; + } + //gf_isom_store_movie_config(video_output_file->isof, 0); + track = gf_isom_new_track(video_output_file->isof, 0, GF_ISOM_MEDIA_VISUAL, video_codec_ctx->time_base.den); + video_output_file->trackID = gf_isom_get_track_id(video_output_file->isof, track); + + video_output_file->timescale = video_codec_ctx->time_base.den; + if (!video_output_file->frame_dur) + video_output_file->frame_dur = video_codec_ctx->time_base.num; + + if (!track) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create new track\n")); + return -1; + } + + ret = gf_isom_set_track_enabled(video_output_file->isof, track, 1); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_track_enabled\n", gf_error_to_string(ret))); + return -1; + } + + ret = dc_gpac_video_write_config(video_output_file, &di, track); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: dc_gpac_video_write_config\n", gf_error_to_string(ret))); + return -1; + } + + gf_isom_set_visual_info(video_output_file->isof, track, di, video_codec_ctx->width, video_codec_ctx->height); + gf_isom_set_sync_table(video_output_file->isof, track); + + ret = gf_isom_setup_track_fragment(video_output_file->isof, track, 1, video_output_file->use_source_timing ? (u32) video_output_file->frame_dur : 1, 0, 0, 0, 0); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_setup_track_fragment\n", gf_error_to_string(ret))); + return -1; + } + + ret = gf_isom_finalize_for_fragment(video_output_file->isof, track); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret))); + return -1; + } + + ret = gf_media_get_rfc_6381_codec_name(video_output_file->isof, track, video_output_file->video_data_conf->codec6381, GF_FALSE, GF_FALSE); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret))); + return -1; + } + + return 0; +} + +int dc_gpac_video_isom_open_seg(VideoOutputFile *video_output_file, char *filename) +{ + GF_Err ret; + ret = gf_isom_start_segment(video_output_file->isof, filename, 1); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_start_segment\n", gf_error_to_string(ret))); + return -1; + } + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Opening new segment %s at UTC "LLU" ms\n", filename, gf_net_get_utc() )); + return 0; +} + +int dc_gpac_video_isom_write(VideoOutputFile *video_output_file) +{ + GF_Err ret; + AVCodecContext *video_codec_ctx = video_output_file->codec_ctx; + + u32 sc_size = 0; + u32 nalu_size = 0; + + u32 buf_len = video_output_file->encoded_frame_size; + u8 *buf_ptr = video_output_file->vbuf; + + GF_BitStream *out_bs = gf_bs_new(NULL, 2 * buf_len, GF_BITSTREAM_WRITE); + nalu_size = gf_media_nalu_next_start_code(buf_ptr, buf_len, &sc_size); + if (nalu_size != 0) { + gf_bs_write_u32(out_bs, nalu_size); + gf_bs_write_data(out_bs, (const char*) buf_ptr, nalu_size); + } + if (sc_size) { + buf_ptr += (nalu_size + sc_size); + buf_len -= (nalu_size + sc_size); + } + + while (buf_len) { + nalu_size = gf_media_nalu_next_start_code(buf_ptr, buf_len, &sc_size); + if (nalu_size != 0) { + gf_bs_write_u32(out_bs, nalu_size); + gf_bs_write_data(out_bs, (const char*) buf_ptr, nalu_size); + } + + buf_ptr += nalu_size; + + if (!sc_size || (buf_len < nalu_size + sc_size)) + break; + buf_len -= nalu_size + sc_size; + buf_ptr += sc_size; + } + + gf_bs_get_content(out_bs, &video_output_file->sample->data, &video_output_file->sample->dataLength); + //video_output_file->sample->data = //(char *) (video_output_file->vbuf + nalu_size + sc_size); + //video_output_file->sample->dataLength = //video_output_file->encoded_frame_size - (sc_size + nalu_size); + + video_output_file->sample->DTS = video_codec_ctx->coded_frame->pkt_dts; + video_output_file->sample->CTS_Offset = (s32) (video_codec_ctx->coded_frame->pts - video_output_file->sample->DTS); + video_output_file->sample->IsRAP = video_codec_ctx->coded_frame->key_frame; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Isom Write: RAP %d , DTS "LLD" CTS offset %d \n", video_output_file->sample->IsRAP, video_output_file->sample->DTS, video_output_file->sample->CTS_Offset)); + + ret = gf_isom_fragment_add_sample(video_output_file->isof, video_output_file->trackID, video_output_file->sample, 1, video_output_file->use_source_timing ? (u32) video_output_file->frame_dur : 1, 0, 0, 0); + if (ret != GF_OK) { + gf_bs_del(out_bs); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_fragment_add_sample\n", gf_error_to_string(ret))); + return -1; + } + + //free data but keep sample structure alive + gf_free(video_output_file->sample->data); + video_output_file->sample->data = NULL; + video_output_file->sample->dataLength = 0; + + gf_bs_del(out_bs); + return 0; +} + +int dc_gpac_video_isom_close_seg(VideoOutputFile *video_output_file) +{ + GF_Err ret; + ret = gf_isom_close_segment(video_output_file->isof, 0, 0, 0, 0, 0, 0, 1, video_output_file->seg_marker, NULL, NULL); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close_segment\n", gf_error_to_string(ret))); + return -1; + } + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Rep %s Closing segment at UTC "LLU" ms\n", video_output_file->rep_id, gf_net_get_utc() )); + + return 0; +} + +int dc_gpac_video_isom_close(VideoOutputFile *video_output_file) +{ + GF_Err ret; + ret = gf_isom_close(video_output_file->isof); + if (ret != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close\n", gf_error_to_string(ret))); + return -1; + } + + return 0; +} + +#endif + + +int dc_raw_h264_open(VideoOutputFile *video_output_file, char *filename) +{ + video_output_file->file = gf_fopen(filename, "w"); + return 0; +} + +int dc_raw_h264_write(VideoOutputFile *video_output_file) +{ + fwrite(video_output_file->vbuf, video_output_file->encoded_frame_size, 1, video_output_file->file); + return 0; +} + +int dc_raw_h264_close(VideoOutputFile *video_output_file) +{ + gf_fclose(video_output_file->file); + return 0; +} + +int dc_ffmpeg_video_muxer_open(VideoOutputFile *video_output_file, char *filename) +{ + AVStream *video_stream; + AVOutputFormat *output_fmt; + + AVCodecContext *video_codec_ctx = video_output_file->codec_ctx; + video_output_file->av_fmt_ctx = NULL; + +// video_output_file->vbr = video_data_conf->bitrate; +// video_output_file->vfr = video_data_conf->framerate; +// video_output_file->width = video_data_conf->width; +// video_output_file->height = video_data_conf->height; +// strcpy(video_output_file->filename, video_data_conf->filename); +// strcpy(video_output_file->codec, video_data_conf->codec); + + /* Find output format */ + output_fmt = av_guess_format(NULL, filename, NULL); + if (!output_fmt) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find suitable output format\n")); + return -1; + } + + video_output_file->av_fmt_ctx = avformat_alloc_context(); + if (!video_output_file->av_fmt_ctx) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate memory for pOutVideoFormatCtx\n")); + return -1; + } + + video_output_file->av_fmt_ctx->oformat = output_fmt; + strcpy(video_output_file->av_fmt_ctx->filename, filename); + + /* Open the output file */ + if (!(output_fmt->flags & AVFMT_NOFILE)) { + if (avio_open(&video_output_file->av_fmt_ctx->pb, filename, URL_WRONLY) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot not open '%s'\n", filename)); + return -1; + } + } + + video_stream = avformat_new_stream(video_output_file->av_fmt_ctx, + video_output_file->codec); + if (!video_stream) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create output video stream\n")); + return -1; + } + + //video_stream->codec = video_output_file->codec_ctx; + + video_stream->codec->codec_id = video_output_file->codec->id; + video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; + video_stream->codec->bit_rate = video_codec_ctx->bit_rate; //video_output_file->video_data_conf->bitrate; + video_stream->codec->width = video_codec_ctx->width; //video_output_file->video_data_conf->width; + video_stream->codec->height = video_codec_ctx->height; //video_output_file->video_data_conf->height; + + video_stream->codec->time_base = video_codec_ctx->time_base; + + video_stream->codec->pix_fmt = PIX_FMT_YUV420P; + video_stream->codec->gop_size = video_codec_ctx->time_base.den; //video_output_file->video_data_conf->framerate; + + av_opt_set(video_stream->codec->priv_data, "preset", "ultrafast", 0); + av_opt_set(video_stream->codec->priv_data, "tune", "zerolatency", 0); + + /* open the video codec */ + if (avcodec_open2(video_stream->codec, video_output_file->codec, NULL) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n")); + return -1; + } + + avformat_write_header(video_output_file->av_fmt_ctx, NULL); + + video_output_file->timescale = video_codec_ctx->time_base.den; + return 0; +} + +int dc_ffmpeg_video_muxer_write(VideoOutputFile *video_output_file) +{ + AVPacket pkt; + AVStream *video_stream = video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx]; + AVCodecContext *video_codec_ctx = video_stream->codec; + + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; + + if (video_codec_ctx->coded_frame->pts != AV_NOPTS_VALUE) { + pkt.pts = av_rescale_q(video_codec_ctx->coded_frame->pts, video_codec_ctx->time_base, video_stream->time_base); + } + + if (video_codec_ctx->coded_frame->key_frame) + pkt.flags |= AV_PKT_FLAG_KEY; + + pkt.stream_index = video_stream->index; + pkt.data = video_output_file->vbuf; + pkt.size = video_output_file->encoded_frame_size; + + // write the compressed frame in the media file + if (av_interleaved_write_frame(video_output_file->av_fmt_ctx, &pkt) != 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Writing frame is not successful\n")); + return -1; + } + + av_free_packet(&pkt); + + return 0; +} + +int dc_ffmpeg_video_muxer_close(VideoOutputFile *video_output_file) +{ + u32 i; + + av_write_trailer(video_output_file->av_fmt_ctx); + + avio_close(video_output_file->av_fmt_ctx->pb); + + // free the streams + for (i = 0; i < video_output_file->av_fmt_ctx->nb_streams; i++) { + avcodec_close(video_output_file->av_fmt_ctx->streams[i]->codec); + av_freep(&video_output_file->av_fmt_ctx->streams[i]->info); + } + + //video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx]->codec = NULL; + avformat_free_context(video_output_file->av_fmt_ctx); + + return 0; +} + +int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, VideoMuxerType muxer_type, int frame_per_segment, int frame_per_fragment, u32 seg_marker, int gdr, int seg_dur, int frag_dur, int frame_dur, int gop_size, int video_cb_size) +{ + char name[GF_MAX_PATH]; + memset(video_output_file, 0, sizeof(VideoOutputFile)); + snprintf(name, sizeof(name), "video encoder %s", video_data_conf->filename); + dc_consumer_init(&video_output_file->consumer, video_cb_size, name); + +#ifndef GPAC_DISABLE_ISOM + video_output_file->sample = gf_isom_sample_new(); + video_output_file->isof = NULL; +#endif + + video_output_file->muxer_type = muxer_type; + + video_output_file->frame_per_segment = frame_per_segment; + video_output_file->frame_per_fragment = frame_per_fragment; + + video_output_file->seg_dur = seg_dur; + video_output_file->frag_dur = frag_dur; + + video_output_file->seg_marker = seg_marker; + video_output_file->gdr = gdr; + video_output_file->gop_size = gop_size; + video_output_file->frame_dur = frame_dur; + + return 0; +} + +int dc_video_muxer_free(VideoOutputFile *video_output_file) +{ +#ifndef GPAC_DISABLE_ISOM + if (video_output_file->isof != NULL) { + gf_isom_close(video_output_file->isof); + } + + gf_isom_sample_del(&video_output_file->sample); +#endif + return 0; +} + +GF_Err dc_video_muxer_open(VideoOutputFile *video_output_file, char *directory, char *id_name, int seg) +{ + char name[GF_MAX_PATH]; + + switch (video_output_file->muxer_type) { + case FFMPEG_VIDEO_MUXER: + snprintf(name, sizeof(name), "%s/%s_%d_ffmpeg.mp4", directory, id_name, seg); + return dc_ffmpeg_video_muxer_open(video_output_file, name); + case RAW_VIDEO_H264: + snprintf(name, sizeof(name), "%s/%s_%d.264", directory, id_name, seg); + return dc_raw_h264_open(video_output_file, name); +#ifndef GPAC_DISABLE_ISOM + case GPAC_VIDEO_MUXER: + snprintf(name, sizeof(name), "%s/%s_%d_gpac.mp4", directory, id_name, seg); + dc_gpac_video_moov_create(video_output_file, name); + return dc_gpac_video_isom_open_seg(video_output_file, NULL); + case GPAC_INIT_VIDEO_MUXER_AVC1: + if (seg == 1) { + snprintf(name, sizeof(name), "%s/%s_init_gpac.mp4", directory, id_name); + dc_gpac_video_moov_create(video_output_file, name); + video_output_file->first_dts_in_fragment = 0; + } + snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg); + return dc_gpac_video_isom_open_seg(video_output_file, name); + case GPAC_INIT_VIDEO_MUXER_AVC3: + if (seg == 0) { + snprintf(name, sizeof(name), "%s/%s_init_gpac.mp4", directory, id_name); + dc_gpac_video_moov_create(video_output_file, name); + video_output_file->first_dts_in_fragment = 0; + } + snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg); + return dc_gpac_video_isom_open_seg(video_output_file, name); +#endif + default: + return GF_BAD_PARAM; + }; + + return -2; +} + +int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 ntp_timestamp) +{ + switch (video_output_file->muxer_type) { + case FFMPEG_VIDEO_MUXER: + return dc_ffmpeg_video_muxer_write(video_output_file); + case RAW_VIDEO_H264: + return dc_raw_h264_write(video_output_file); +#ifndef GPAC_DISABLE_ISOM + case GPAC_VIDEO_MUXER: + case GPAC_INIT_VIDEO_MUXER_AVC1: + case GPAC_INIT_VIDEO_MUXER_AVC3: + if (video_output_file->use_source_timing) { + GF_Err ret; + if (!video_output_file->fragment_started) { + video_output_file->fragment_started = 1; + ret = gf_isom_start_fragment(video_output_file->isof, 1); + if (ret < 0) + return -1; + + //insert UTC for each fragment + if (ntp_timestamp) { + gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, ntp_timestamp, video_output_file->codec_ctx->coded_frame->pts); + } + + video_output_file->first_dts_in_fragment = video_output_file->codec_ctx->coded_frame->pkt_dts; + if (!video_output_file->segment_started) { + video_output_file->pts_at_segment_start = video_output_file->codec_ctx->coded_frame->pts; + video_output_file->segment_started = 1; + if (!video_output_file->nb_segments) { + video_output_file->pts_at_first_segment = video_output_file->pts_at_segment_start; + } + +#ifndef GPAC_DISABLE_LOG + if (ntp_timestamp && gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_INFO)) { + if (!video_output_file->ntp_at_first_dts) { + video_output_file->ntp_at_first_dts = ntp_timestamp; + } else { + s32 ntp_diff = gf_net_get_ntp_diff_ms(video_output_file->ntp_at_first_dts); + s32 ts_diff = (s32) ( 1000 * (video_output_file->codec_ctx->coded_frame->pts - video_output_file->pts_at_first_segment) / video_output_file->timescale ); + + s32 diff_ms = ts_diff - ntp_diff; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Video Segment start NTP diff: %d ms TS diff: %d ms drift: %d ms\n", ntp_diff, ts_diff, diff_ms)); + } + } +#endif + } + gf_isom_set_traf_base_media_decode_time(video_output_file->isof, video_output_file->trackID, video_output_file->first_dts_in_fragment); + } + + if (dc_gpac_video_isom_write(video_output_file) < 0) { + return -1; + } + video_output_file->last_pts = video_output_file->codec_ctx->coded_frame->pts; + video_output_file->last_dts = video_output_file->codec_ctx->coded_frame->pkt_dts; + + if (( video_output_file->last_dts - video_output_file->first_dts_in_fragment + video_output_file->frame_dur) * 1000 >= video_output_file->frag_dur * video_output_file->timescale) { + gf_isom_flush_fragments(video_output_file->isof, 1); + video_output_file->fragment_started = 0; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Flushed fragment at UTC "LLU" ms - First DTS "LLU" last PTS "LLU"\n", gf_net_get_utc(), video_output_file->first_dts_in_fragment, video_output_file->codec_ctx->coded_frame->pts)); + } + + //we may have rounding errors on the input PTS :( add half frame dur safety + + //flush segments based on the cumultated duration , to avoid drift + if (1000 * ( video_output_file->last_pts - video_output_file->pts_at_first_segment + 3*video_output_file->frame_dur/2) / video_output_file->timescale >= (video_output_file->nb_segments+1)*video_output_file->seg_dur ) { + return 1; + } +#if 0 + if (1000 * ( video_output_file->last_pts - video_output_file->pts_at_segment_start + 3*video_output_file->frame_dur/2) /video_output_file->timescale >= video_output_file->seg_dur ) { + return 1; + } +#endif + return 0; + } + + if (frame_nb % video_output_file->frame_per_fragment == 0) { + gf_isom_start_fragment(video_output_file->isof, 1); + + if (!video_output_file->segment_started) { + video_output_file->pts_at_segment_start = video_output_file->codec_ctx->coded_frame->pts; + video_output_file->segment_started = 1; + + if (ntp_timestamp) { + gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, ntp_timestamp, video_output_file->pts_at_segment_start); + } + } + + + gf_isom_set_traf_base_media_decode_time(video_output_file->isof, video_output_file->trackID, video_output_file->first_dts_in_fragment); + video_output_file->first_dts_in_fragment += video_output_file->frame_per_fragment; + } + + dc_gpac_video_isom_write(video_output_file); + + if (frame_nb % video_output_file->frame_per_fragment == video_output_file->frame_per_fragment - 1) { + gf_isom_flush_fragments(video_output_file->isof, 1); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Flushed fragment to disk at UTC "LLU" ms - last coded frame PTS "LLU"\n", gf_net_get_utc(), video_output_file->codec_ctx->coded_frame->pts)); + } + + if (frame_nb + 1 == video_output_file->frame_per_segment) + return 1; + + return 0; +#endif + + default: + return -2; + } + + return -2; +} + +int dc_video_muxer_close(VideoOutputFile *video_output_file) +{ + video_output_file->fragment_started = video_output_file->segment_started = 0; + video_output_file->nb_segments++; + + switch (video_output_file->muxer_type) { + case FFMPEG_VIDEO_MUXER: + return dc_ffmpeg_video_muxer_close(video_output_file); + case RAW_VIDEO_H264: + return dc_raw_h264_close(video_output_file); +#ifndef GPAC_DISABLE_ISOM + case GPAC_VIDEO_MUXER: + dc_gpac_video_isom_close_seg(video_output_file); + return dc_gpac_video_isom_close(video_output_file); + case GPAC_INIT_VIDEO_MUXER_AVC1: + case GPAC_INIT_VIDEO_MUXER_AVC3: + return dc_gpac_video_isom_close_seg(video_output_file); +#endif + default: + return -2; + } + + return -2; +} diff --git a/applications/dashcast/video_muxer.h b/applications/dashcast/video_muxer.h new file mode 100644 index 0000000..08ded74 --- /dev/null +++ b/applications/dashcast/video_muxer.h @@ -0,0 +1,114 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef VIDEO_MUXER_H_ +#define VIDEO_MUXER_H_ + +#include "../../modules/ffmpeg_in/ffmpeg_in.h" +#include "libavformat/avformat.h" +#include "libavdevice/avdevice.h" +#include "libswscale/swscale.h" +#include "libavutil/mathematics.h" +#include +#include + +#include "video_scaler.h" + +typedef enum { + FFMPEG_VIDEO_MUXER, + RAW_VIDEO_H264, + GPAC_VIDEO_MUXER, + GPAC_INIT_VIDEO_MUXER_AVC1, + GPAC_INIT_VIDEO_MUXER_AVC3 +} VideoMuxerType; + +/* + * VideoOutputFile structure has the data needed to encode video frames and write them on the file. + * It reads the data from a circular buffer so it needs to keep the index to that circular buffer. This index is + * available in Consumer data structure. + */ +typedef struct { + VideoDataConf *video_data_conf; + VideoMuxerType muxer_type; + + /* file format context structure */ + AVFormatContext *av_fmt_ctx; + AVCodecContext *codec_ctx; + AVCodec *codec; + + FILE *file; + +#ifndef GPAC_DISABLE_ISOM + GF_ISOFile *isof; + GF_ISOSample *sample; +#endif + + u32 trackID; + /* Index of the video stream in the file */ + int vstream_idx; + /* keeps the index with which encoder access to the circular buffer (as a consumer) */ + Consumer consumer; + + /* Variables that encoder needs to encode data */ + uint8_t *vbuf; + int vbuf_size; + int encoded_frame_size; + + int frame_per_fragment; + int frame_per_segment; + + int seg_dur; + int frag_dur; + + u64 first_dts_in_fragment; + u64 ntp_at_first_dts; + + u32 seg_marker; + + int gop_size; + int gdr; + + Bool use_source_timing; + + u64 pts_at_segment_start, pts_at_first_segment; + u64 last_pts, last_dts; + u64 frame_dur; + u32 timescale; + u32 nb_segments; + Bool fragment_started, segment_started; + const char *rep_id; +} VideoOutputFile; + +int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, VideoMuxerType muxer_type, int frame_per_segment, int frame_per_fragment, u32 seg_marker, int gdr, int seg_dur, int frag_dur, int frame_dur, int gop_size, int video_cb_size); + +int dc_video_muxer_free(VideoOutputFile *video_output_file); + +int dc_video_muxer_open(VideoOutputFile *video_output_file, char *directory, char *id_name, int seg); + +int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 ntp_timestamp); + +int dc_video_muxer_close(VideoOutputFile *video_output_file); + +#endif /* VIDEO_MUXER_H_ */ diff --git a/applications/dashcast/video_scaler.c b/applications/dashcast/video_scaler.c new file mode 100644 index 0000000..0135d9d --- /dev/null +++ b/applications/dashcast/video_scaler.c @@ -0,0 +1,273 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "video_scaler.h" + + +#ifdef GPAC_USE_LIBAV +#define av_frame_free av_free +#endif + +VideoScaledDataNode * dc_video_scaler_node_create(int width, int height, int crop_x, int crop_y, int pix_fmt) +{ + VideoScaledDataNode *video_scaled_data_node = gf_malloc(sizeof(VideoDataNode)); + if (video_scaled_data_node) { + video_scaled_data_node->v_frame = FF_ALLOC_FRAME(); + if (crop_x || crop_y) { + video_scaled_data_node->cropped_frame = FF_ALLOC_FRAME(); + } else { + video_scaled_data_node->cropped_frame = NULL; + } + } + if (!video_scaled_data_node || !video_scaled_data_node->v_frame || ((crop_x || crop_y) && !video_scaled_data_node->cropped_frame)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate VideoNode!\n")); + av_frame_free(&video_scaled_data_node->v_frame); + av_frame_free(&video_scaled_data_node->cropped_frame); + gf_free(video_scaled_data_node); + return NULL; + } + + /* Determine required buffer size and allocate buffer */ + avpicture_alloc((AVPicture*)video_scaled_data_node->v_frame, pix_fmt, width, height); + if (video_scaled_data_node->cropped_frame) { + avpicture_alloc((AVPicture*)video_scaled_data_node->cropped_frame, pix_fmt, width-crop_x, height-crop_y); + } + + return video_scaled_data_node; +} + +void dc_video_scaler_node_destroy(VideoScaledDataNode *video_scaled_data_node) +{ +#ifndef GPAC_USE_LIBAV + av_frame_free(&video_scaled_data_node->v_frame); +#endif + gf_free(video_scaled_data_node); +} + +void dc_video_scaler_list_init(VideoScaledDataList *video_scaled_data_list, GF_List * video_lst) +{ + u32 i, j; + int found; + + video_scaled_data_list->size = 0; + video_scaled_data_list->video_scaled_data = NULL; + + for (i=0; isize; j++) { + if ( video_scaled_data_list->video_scaled_data[j]->out_height == video_data_conf->height + && video_scaled_data_list->video_scaled_data[j]->out_width == video_data_conf->width) { + found = 1; + video_scaled_data_list->video_scaled_data[j]->num_consumers++; + break; + } + } + if (!found) { + VideoScaledData *video_scaled_data; + GF_SAFEALLOC(video_scaled_data, VideoScaledData); + video_scaled_data->out_width = video_data_conf->width; + video_scaled_data->out_height = video_data_conf->height; + video_scaled_data->num_consumers = 1; + + video_scaled_data_list->video_scaled_data = gf_realloc(video_scaled_data_list->video_scaled_data, (video_scaled_data_list->size+1)*sizeof(VideoScaledData*)); + + video_scaled_data_list->video_scaled_data[video_scaled_data_list->size] = video_scaled_data; + video_scaled_data_list->size++; + } + } +} + +void dc_video_scaler_list_destroy(VideoScaledDataList *video_scaled_data_list) +{ + u32 i; + for (i=0; isize; i++) + gf_free(video_scaled_data_list->video_scaled_data[i]); + + gf_free(video_scaled_data_list->video_scaled_data); +} + +void dc_video_scaler_end_signal(VideoScaledData *video_scaled_data) +{ + dc_producer_end_signal(&video_scaled_data->producer, &video_scaled_data->circular_buf); + dc_producer_unlock_previous(&video_scaled_data->producer, &video_scaled_data->circular_buf); +} + +int dc_video_scaler_data_init(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int max_source, int video_cb_size) +{ + int i; + char name[GF_MAX_PATH]; + snprintf(name, sizeof(name), "video scaler %dx%d", video_scaled_data->out_width, video_scaled_data->out_height); + + dc_producer_init(&video_scaled_data->producer, video_cb_size, name); + dc_consumer_init(&video_scaled_data->consumer, video_cb_size, name); + + video_scaled_data->num_producers = max_source; + video_scaled_data->out_pix_fmt = PIX_FMT_YUV420P; + GF_SAFE_ALLOC_N(video_scaled_data->vsprop, max_source, VideoScaledProp); + memset(video_scaled_data->vsprop, 0, max_source * sizeof(VideoScaledProp)); + + dc_circular_buffer_create(&video_scaled_data->circular_buf, video_cb_size, video_input_data->circular_buf.mode, video_scaled_data->num_consumers); + for (i=0; icircular_buf.list[i].data = dc_video_scaler_node_create(video_scaled_data->out_width, video_scaled_data->out_height, video_input_data->vprop[i].crop_x, video_input_data->vprop[i].crop_y, video_scaled_data->out_pix_fmt); + } + + return 0; +} + +int dc_video_scaler_data_set_prop(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int index) +{ + video_scaled_data->vsprop[index].in_width = video_input_data->vprop[index].width - video_input_data->vprop[index].crop_x; + video_scaled_data->vsprop[index].in_height = video_input_data->vprop[index].height - video_input_data->vprop[index].crop_y; + video_scaled_data->vsprop[index].in_pix_fmt = video_input_data->vprop[index].pix_fmt; + + video_scaled_data->sar = video_input_data->vprop[index].sar; + + video_scaled_data->vsprop[index].sws_ctx = sws_getContext( + video_scaled_data->vsprop[index].in_width, + video_scaled_data->vsprop[index].in_height, + video_scaled_data->vsprop[index].in_pix_fmt, + video_scaled_data->out_width, video_scaled_data->out_height, + video_scaled_data->out_pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL); + if (video_scaled_data->vsprop[index].sws_ctx == NULL) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize the conversion context!\n")); + return -1; + } + + return 0; +} + +int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *video_scaled_data) +{ + int ret, index, src_height; + VideoDataNode *video_data_node; + VideoScaledDataNode *video_scaled_data_node; + AVFrame *src_vframe; + + //step 1: try to lock output slot. If none available, return .... + if (video_input_data->circular_buf.size > 1) + dc_consumer_unlock_previous(&video_scaled_data->consumer, &video_input_data->circular_buf); + + ret = dc_producer_lock(&video_scaled_data->producer, &video_scaled_data->circular_buf); + //not ready + if (ret<0) { + return -1; + } + dc_producer_unlock_previous(&video_scaled_data->producer, &video_scaled_data->circular_buf); + + //step 2: lock input + ret = dc_consumer_lock(&video_scaled_data->consumer, &video_input_data->circular_buf); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video scaler got an end of input tbuffer!\n")); + return -2; + } + + //step 3 - grab source and dest images + video_data_node = (VideoDataNode*)dc_consumer_consume(&video_scaled_data->consumer, &video_input_data->circular_buf); + video_scaled_data_node = (VideoScaledDataNode*)dc_producer_produce(&video_scaled_data->producer, &video_scaled_data->circular_buf); + index = video_data_node->source_number; + + video_scaled_data->frame_duration = video_input_data->frame_duration; + + //crop if necessary + if (video_input_data->vprop[index].crop_x || video_input_data->vprop[index].crop_y) { +#if 0 + av_frame_copy_props(video_scaled_data_node->cropped_frame, video_data_node->vframe); + video_scaled_data_node->cropped_frame->width = video_input_data->vprop[index].width - video_input_data->vprop[index].crop_x; + video_scaled_data_node->cropped_frame->height = video_input_data->vprop[index].height - video_input_data->vprop[index].crop_y; +#endif + if (av_picture_crop((AVPicture*)video_scaled_data_node->cropped_frame, (AVPicture*)video_data_node->vframe, PIX_FMT_YUV420P, video_input_data->vprop[index].crop_y, video_input_data->vprop[index].crop_x) < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video scaler: error while cropping picture.\n")); + return -1; + } + src_vframe = video_scaled_data_node->cropped_frame; + src_height = video_input_data->vprop[index].height - video_input_data->vprop[index].crop_y; + } else { + assert(!video_scaled_data_node->cropped_frame); + src_vframe = video_data_node->vframe; + src_height = video_input_data->vprop[index].height; + } + + + //rescale the cropped frame + ret = sws_scale(video_scaled_data->vsprop[index].sws_ctx, + (const uint8_t * const *)src_vframe->data, src_vframe->linesize, 0, src_height, + video_scaled_data_node->v_frame->data, video_scaled_data_node->v_frame->linesize); + + if (!ret) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video scaler: error while resizing picture.\n")); + return -1; + } + video_scaled_data_node->v_frame->pts = video_data_node->vframe->pts; + + if (video_data_node->nb_raw_frames_ref) { + if (video_data_node->nb_raw_frames_ref==1) { +#ifndef GPAC_USE_LIBAV + av_frame_unref(video_data_node->vframe); +#endif + av_free_packet(&video_data_node->raw_packet); + } + video_data_node->nb_raw_frames_ref--; + } + + dc_consumer_advance(&video_scaled_data->consumer); + dc_producer_advance(&video_scaled_data->producer, &video_scaled_data->circular_buf); + + if (video_input_data->circular_buf.size == 1) + dc_consumer_unlock_previous(&video_scaled_data->consumer, &video_input_data->circular_buf); + return 0; +} + +int dc_video_scaler_data_destroy(VideoScaledData *video_scaled_data) +{ + int i; + for (i=0; i<(int) video_scaled_data->circular_buf.size; i++) { + if (video_scaled_data->circular_buf.list) { + dc_video_scaler_node_destroy(video_scaled_data->circular_buf.list[i].data); + } + } + + for (i=0 ; inum_producers; i++) { + if (video_scaled_data->vsprop[i].sws_ctx) + av_free(video_scaled_data->vsprop[i].sws_ctx); + } + gf_free(video_scaled_data->vsprop); + //av_free(video_scaled_data->sws_ctx); + + dc_circular_buffer_destroy(&video_scaled_data->circular_buf); + + return 0; +} + +VideoScaledData * dc_video_scaler_get_data(VideoScaledDataList *video_scaled_data_list, int width, int height) +{ + u32 i; + for (i=0; isize; i++) { + if (video_scaled_data_list->video_scaled_data[i]->out_width == width && video_scaled_data_list->video_scaled_data[i]->out_height == height) + return video_scaled_data_list->video_scaled_data[i]; + } + + return NULL; +} diff --git a/applications/dashcast/video_scaler.h b/applications/dashcast/video_scaler.h new file mode 100644 index 0000000..3442e59 --- /dev/null +++ b/applications/dashcast/video_scaler.h @@ -0,0 +1,168 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Arash Shafiei + * Copyright (c) Telecom ParisTech 2000-2013 + * All rights reserved + * + * This file is part of GPAC / dashcast + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef VIDEO_SCALER_H_ +#define VIDEO_SCALER_H_ + +#include +#include + +#include "video_data.h" + + +typedef struct { + /* scaler of the libav */ + struct SwsContext *sws_ctx; + /* width, height, and the pixel format of the scaled video */ + int in_width; + int in_height; + int in_pix_fmt; +} VideoScaledProp; + +/* + * VideoScaledData keeps a circular buffer + * of video frame with a defined resolution. + */ +typedef struct { + VideoScaledProp *vsprop; + + int out_width; + int out_height; + int out_pix_fmt; + AVRational sar; + + /* scaler of the libav */ + //struct SwsContext * sws_ctx; + /* width, height, and the pixel format of the scaled video */ + //int width; + //int height; + //int pix_fmt; + + /* circular buffer containing the scaled video frames */ + CircularBuffer circular_buf; + + /* Scaler is a consumer and also producer. + * It consumes from the video input data and it produces the video scaled data. + * So it deals with two circular buffer and we need to keep the index for both. */ + Producer producer; + Consumer consumer; + + /* The number of consumers of this circular buffer. + * (Which are the encoders who are using this resolution) */ + int num_consumers; + int num_producers; + + u64 frame_duration; +} VideoScaledData; + +/* + * Each node in a circular buffer is a pointer. + * To use the circular buffer for scaled video frame we must define the node. This structure contains the data needed to encode a video frame. + */ +typedef struct { + AVFrame *v_frame; + AVFrame *cropped_frame; +} VideoScaledDataNode; + +/* + * A list of pointers to scaled video data. + */ +typedef struct { + VideoScaledData **video_scaled_data; + u32 size; +} VideoScaledDataList; + +/* + * Read the configuration file info and fill the video scaled data list with all the resolution available. + * Each resolution is associated to a circular buffer in a video scaled data. + * + * @param cmd_data [in] Command data which contains the configuration file info + * @param video_scaled_data_list [out] the list to be filled + */ +void dc_video_scaler_list_init(VideoScaledDataList *video_scaled_data_list, GF_List *video_lst); + +/* + * Destroy a video scaled data list. + * + * @param video_scaled_data_list [in] the list to be destroyed. + */ +void dc_video_scaler_list_destroy(VideoScaledDataList *video_scaled_data_list); + +/* + * Signal to all the users of the circular buffer in the VideoScaledData + * which the current node is the last node to consume. + * + * @param video_scaled_data [in] the structure to be signaled on. + */ +void dc_video_scaler_end_signal(VideoScaledData *video_scaled_data); + +/* + * Initialize a VideoScaledData. + * + * @param video_input_data [in] contains the info of the input video. + * @param video_scaled_data [out] structure to be initialized. + * + * @return 0 on success, -1 on failure. + * + * @note Must use dc_video_scaler_data_destroy to free memory. + */ +int dc_video_scaler_data_init(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int num_producers, int video_cb_size); + +/* + * Set properties of a VideoScaledData. + */ +int dc_video_scaler_data_set_prop(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int index); + +/* + * Get a frame from the circular buffer on the input video, + * scale it and put the result on the circular buffer of the + * video scaled data + * + * @param video_input_data [in] contains input frames + * @param video_scaled_data [out] contains scaled frames + * + * return 0 on success, -2 if the node is the last node to scale + */ +int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *video_scaled_data); + +/* + * Destroy a VideoScaledData + * + * @param video_scaled_data [in] structure to be destroyed. + */ +int dc_video_scaler_data_destroy(VideoScaledData *video_scaled_data); + +/* + * Return the VideoScaledData from the list which has width and height + * + * @param video_scaled_data_list [in] video scaled data list + * @param width [in] frame width + * @param height [in] frame height + * + * @return a VideoScaledData which corresponds to the width and height on success, NULL on failure + */ +VideoScaledData * dc_video_scaler_get_data(VideoScaledDataList *video_scaled_data_list, int width, int height); + +#endif /* VIDEO_SCALER_H_ */ diff --git a/applications/generators/MPEG4/MPEG4Gen.dsp b/applications/generators/MPEG4/MPEG4Gen.dsp new file mode 100644 index 0000000..e5a7d9c --- /dev/null +++ b/applications/generators/MPEG4/MPEG4Gen.dsp @@ -0,0 +1,98 @@ +# Microsoft Developer Studio Project File - Name="MPEG4Gen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=MPEG4Gen - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "MPEG4Gen.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MPEG4Gen.mak" CFG="MPEG4Gen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MPEG4Gen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "MPEG4Gen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MPEG4Gen - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Obj/W32Rel" +# PROP Intermediate_Dir "Obj/W32Rel" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "MPEG4Gen - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Obj/W32Deb" +# PROP Intermediate_Dir "Obj/W32Deb" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "MPEG4Gen - Win32 Release" +# Name "MPEG4Gen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\utils\list.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# End Target +# End Project diff --git a/applications/generators/MPEG4/MPEG4Gen.dsw b/applications/generators/MPEG4/MPEG4Gen.dsw new file mode 100644 index 0000000..e3bd23b --- /dev/null +++ b/applications/generators/MPEG4/MPEG4Gen.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "MPEG4Gen"=.\MPEG4Gen.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/generators/MPEG4/Makefile b/applications/generators/MPEG4/Makefile new file mode 100644 index 0000000..4bf4ec6 --- /dev/null +++ b/applications/generators/MPEG4/Makefile @@ -0,0 +1,52 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/generators/MPEG4 + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=MPEG4Gen$(EXE) +else +EXT= +PROG=MPEG4Gen +endif + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac + + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + + +clean: + rm -f $(OBJS) $(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/generators/MPEG4/main.c b/applications/generators/MPEG4/main.c new file mode 100644 index 0000000..a3f7b0e --- /dev/null +++ b/applications/generators/MPEG4/main.c @@ -0,0 +1,1862 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / MPEG4 Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +#undef _DEBUG +#undef DEBUG + +#include + + +#include + + +#define COPYRIGHT_SCENE "/*\n * GPAC - Multimedia Framework C SDK\n *\n * Authors: Jean Le Feuvre\n * Copyright (c) Telecom ParisTech 2000-2012\n * All rights reserved\n *\n * This file is part of GPAC / Scene Graph sub-project\n *\n * GPAC is free software; you can redistribute it and/or modify\n * it under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2, or (at your option)\n * any later version.\n *\n * GPAC is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details. \n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; see the file COPYING. If not, write to\n * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n" +#define COPYRIGHT_BIFS "/*\n * GPAC - Multimedia Framework C SDK\n *\n * Authors: Jean Le Feuvre\n * Copyright (c) Telecom ParisTech 2000-2012\n * All rights reserved\n *\n * This file is part of GPAC / BIFS codec sub-project\n *\n * GPAC is free software; you can redistribute it and/or modify\n * it under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2, or (at your option)\n * any later version.\n *\n * GPAC is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details. \n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; see the file COPYING. If not, write to\n * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n" + +static char *CurrentLine; + +void PrintUsage() +{ + printf("MPEG4Gen [-p file] [template_file_v1 (template_file_v2 ...) ]\n" + "\nGPAC MPEG4 Scene Graph generator. Usage:\n" + "-p: listing file of nodes to exclude from tables\n" + "Template files MUST be fed in order\n" + "\n" + "Generated Files are directly updated in the GPAC distribution - do NOT try to change this\n\n" + "Written by Jean Le Feuvre - Copyright (c) Telecom ParisTech 2000-2012\n" + ); +} + +//a node field +typedef struct +{ + char type[50]; + //SFxxx, MFxxx + char familly[50]; + //name + char name[1000]; + //default value + char def[100]; + //bounds + u32 hasBounds; + char b_min[20]; + char b_max[20]; + //Quant + u32 hasQuant; + char quant_type[50]; + char qt13_bits[50]; + //Anim + u32 hasAnim; + u32 AnimType; + +} BField; + +//NDTs + +//a BIFS node +typedef struct +{ + char name[1000]; + //NDT info. NDT are created in alphabetical order + GF_List *NDT; + //0: normal, 1: special + u32 codingType; + u32 version; + + GF_List *Fields; + + //coding types + u8 hasDef, hasIn, hasOut, hasDyn; + u8 hasAQInfo; + + u8 hasDefault; + + u8 skip_impl; + + char Child_NDT_Name[1000]; +} BNode; + + +void skip_sep(char *sep) +{ + //skip separaors + while (*CurrentLine && strchr(sep, *CurrentLine)) { + CurrentLine = CurrentLine + 1; + //end of line - no token + if (*CurrentLine == '\n') return; + } +} + +//note that we increment the line no matter what +u32 GetNextToken(char *token, char *sep) +{ + u32 i , j = 0; + + strcpy(token, ""); + + //skip separaors + while (*CurrentLine && strchr(sep, *CurrentLine)) { + CurrentLine = CurrentLine + 1; + j ++; + //end of line - no token + if (*CurrentLine == '\n') return 0; + } + + //copy token untill next blank + i=0; + while (1) { + //bad line + if (! *CurrentLine) { + token[i] = 0; + return 0; + } + //end of token or end of line + if (strchr(sep, *CurrentLine) || (*CurrentLine == '\n') ) { + token[i] = 0; + CurrentLine = CurrentLine + 1; + return i; + } else { + token[i] = *CurrentLine; + } + CurrentLine = CurrentLine + 1; + i++; + j++; + } + return 1; +} + + +char szFixedVal[5000]; +char *GetFixedPrintout(char *val) +{ + if (!strcmp(val, "FIX_MIN") || !strcmp(val, "FIX_MAX")) return val; + /*composite texture...*/ + if (!strcmp(val, "65535")) return "FIX_MAX /*WARNING: modified to allow 16.16 fixed point version!!*/"; + sprintf(szFixedVal, "FLT2FIX(%s)", val); + return szFixedVal; +} + +BField *BlankField() +{ + BField *n = gf_malloc(sizeof(BField)); + memset(n, 0, sizeof(BField)); + return n; +} + + +BNode *BlankNode() +{ + BNode *n = gf_malloc(sizeof(BNode)); + memset(n, 0, sizeof(BNode)); + n->NDT = gf_list_new(); + n->Fields = gf_list_new(); + return n; +} + +u8 IsNDT(GF_List *NDTs, char *famName) +{ + u32 i; + char *ndtName; + for (i=0; i\n\n"); + fprintf(f, "#ifndef GPAC_DISABLE_VRML\n\n"); + + + //write all tags + fprintf(f, "\n\nenum {\n"); + + for (i=0; iname); + else + fprintf(f, "\tTAG_MPEG4_%s = GF_NODE_RANGE_FIRST_MPEG4", n->name); + } + fprintf(f, ",\n\tTAG_LastImplementedMPEG4\n};\n\n"); + + for (i=0; iskip_impl) continue; + + fprintf(f, "typedef struct _tag%s\n{\n", n->name); + fprintf(f, "\tBASE_NODE\n"); + + /*write children field*/ + for (j=0; jFields); j++) { + bf = gf_list_get(n->Fields, j); + if (!stricmp(bf->name, "addChildren") || !strcmp(bf->name, "removeChildren")) continue; + if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) { + fprintf(f, "\tVRML_CHILDREN\n"); + break; + } + } + for (j=0; jFields); j++) { + bf = gf_list_get(n->Fields, j); + + if (!strcmp(bf->name, "addChildren") || !strcmp(bf->name, "removeChildren")) continue; + if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) continue; + + //write remaining fields + //eventIn fields are handled as pointer to functions, called by the route manager + if (!strcmp(bf->type, "eventIn")) { + if (strstr(bf->familly, "Node")) { + fprintf(f, "\tGF_Node *%s;\t/*eventIn*/\n",bf->name); + } else { + fprintf(f, "\t%s %s;\t/*eventIn*/\n", bf->familly, bf->name); + } + fprintf(f, "\tvoid (*on_%s)(GF_Node *pThis, struct _route *route);\t/*eventInHandler*/\n", bf->name); + } else if (!strcmp(bf->type, "eventOut")) { + //eventOut fields are handled as an opaque stack pointing to the route manager + //this will be refined once the route is in place + //we will likely need a function such as: + // void SignalRoute(route_stack, node, par) + fprintf(f, "\t%s %s;\t/*eventOut*/\n", bf->familly, bf->name); + } else if (strstr(bf->familly, "Node")) { + //this is a POINTER to a node + if (strstr(bf->familly, "SF")) { + fprintf(f, "\tGF_Node *%s;\t/*%s*/\n", bf->name, bf->type); + } else { + //this is a POINTER to a chain + fprintf(f, "\tGF_ChildNodeItem *%s;\t/*%s*/\n", bf->name, bf->type); + } + } else { + fprintf(f, "\t%s %s;\t/*%s*/\n", bf->familly, bf->name, bf->type); + } + } + if (!strcmp(n->name, "CacheTexture")) { + fprintf(f, "\t/*GPAC private*/\n"); + fprintf(f, "\tu8 *data;\n"); + fprintf(f, "\tu32 data_len;\n"); + } + if (!strcmp(n->name, "BitWrapper")) { + fprintf(f, "\t/*GPAC private*/\n"); + fprintf(f, "\tu32 buffer_len;\n"); + } + fprintf(f, "} M_%s;\n\n\n", n->name); + } + + + hasViewport = 0; + //all NDTs are defined in v1 + fprintf(f, "/*NodeDataType tags*/\nenum {\n"); + for (i=0; i not generated + if (!hasViewport) fprintf(f, ",\n\tNDT_SFViewportNode"); + fprintf(f, "\n};\n\n"); + + + fprintf(f, "/*All BIFS versions handled*/\n"); + fprintf(f, "#define GF_BIFS_NUM_VERSION\t\t%d\n\n", NumVersions); + fprintf(f, "enum {\n"); + for (i=0; iNDT); i++) { + ndt = gf_list_get(node->NDT, i); + if (!strcmp(ndt, NDTName)) return 1; + } + return 0; +} + +u32 GetBitsCount(u32 MaxVal) +{ + u32 k=0; + + while ((s32) MaxVal > ((1<version != Version) continue; + if (!IsNodeInTable(n, NDTName)) continue; + nodeCount++; + } + return nodeCount; + +} + +void WriteNDT_H(FILE *f, GF_List *BNodes, GF_List *NDTs, u32 Version) +{ + u32 i, j, first, count; + char *NDTName; + BNode *n; + + + fprintf(f, "\n\n/* NDT BIFS Version %d */\n\n", Version); + + //for all NDTs + for (i=0; i 2) { + count -= 1; + } + if (!count) continue; + + //numBits + fprintf(f, "#define %s_V%d_NUMBITS\t\t%d\n", NDTName, Version, GetBitsCount(count + ( (Version == 2) ? 1 : 0) ) ); + fprintf(f, "#define %s_V%d_Count\t%d\n\n", NDTName, Version, count); + + fprintf(f, "static const u32 %s_V%d_TypeToTag[%d] = {\n", NDTName, Version, count); + first = 1; + //browse each node. + for (j=0; jversion != Version) continue; + if (!IsNodeInTable(n, NDTName)) continue; + + if (first) { + fprintf(f, " TAG_MPEG4_%s", n->name); + first = 0; + } else { + fprintf(f, ", TAG_MPEG4_%s", n->name); + } + } + fprintf(f, "\n};\n\n"); + + } + + fprintf(f, "\nu32 NDT_V%d_GetNumBits(u32 NDT_Tag);\n", Version); + fprintf(f, "u32 NDT_V%d_GetNodeTag(u32 Context_NDT_Tag, u32 NodeType);\n", Version); + fprintf(f, "u32 NDT_V%d_GetNodeType(u32 NDT_Tag, u32 NodeTag);\n", Version); + + fprintf(f, "\n\n"); +} + +//write the NDTs functions for v1 nodes +//all our internal handling is in TAG_MPEG4_#nodename because we need an homogeneous +//namespace for all nodes (v1, v2, v3 and v4) +//the NDT functions will perform the translation from the NDT value to the absolute +//TAG of the node +void WriteNDT_Dec(FILE *f, GF_List *BNodes, GF_List *NDTs, u32 Version) +{ + char *NDTName; + u32 i, count; + + //NodeTag complete translation + fprintf(f, "\n\n\nu32 NDT_V%d_GetNodeTag(u32 Context_NDT_Tag, u32 NodeType)\n{\n\tif (!NodeType) return 0;\n", Version); + + //handle version + fprintf(f, "\t/* adjust according to the table version */\n"); + if (Version == 2) { + fprintf(f, "\t/* v2: 0 reserved for extensions, 1 reserved for protos */\n"); + fprintf(f, "\tif (NodeType == 1) return 0;\n"); + fprintf(f, "\tNodeType -= 2;\n"); + } else { + fprintf(f, "\t/* v%d: 0 reserved for extensions */\n", Version); + fprintf(f, "\tNodeType -= 1;\n"); + } + + fprintf(f, "\tswitch (Context_NDT_Tag) {\n"); + + for (i=0; i 2) { + count -= 1; + } + if (!count) continue; + + fprintf(f, "\tcase NDT_%s:\n\t\tif (NodeType >= %s_V%d_Count) return 0;\n", NDTName, NDTName, Version); + fprintf(f, "\t\treturn %s_V%d_TypeToTag[NodeType];\n", NDTName, Version); + } + fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}"); + + //NDT codec bits + fprintf(f, "\n\n\nu32 NDT_V%d_GetNumBits(u32 NDT_Tag)\n{\n\tswitch (NDT_Tag) {\n", Version); + + for (i=0; i 2) { + count -= 1; + } + if (!count) continue; + + fprintf(f, "\tcase NDT_%s:\n\t\treturn %s_V%d_NUMBITS;\n", NDTName, NDTName, Version); + } + /*all tables have 1 node in v2 for proto coding*/ + fprintf(f, "\tdefault:\n\t\treturn %d;\n\t}\n}\n\n", (Version==2) ? 1 : 0); +} + + +void WriteNDT_Enc(FILE *f, GF_List *BNodes, GF_List *NDTs, u32 Version) +{ + u32 i, count; + char *NDTName; + + fprintf(f, "u32 NDT_V%d_GetNodeType(u32 NDT_Tag, u32 NodeTag)\n{\n\tif(!NDT_Tag || !NodeTag) return 0;\n\tswitch(NDT_Tag) {\n", Version); + for (i=0; i 2) { + count -= 1; + } + if (!count) continue; + fprintf(f, "\tcase NDT_%s:\n\t\treturn ALL_GetNodeType(%s_V%d_TypeToTag, %s_V%d_Count, NodeTag, GF_BIFS_V%d);\n", NDTName, NDTName, Version, NDTName, Version, Version); + } + fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n"); +} + + + +void WriteNodeFields(FILE *f, BNode *n) +{ + u32 i, first; + BField *bf; + u32 NbDef, NbIn, NbOut, NbDyn, hasAQ; + + NbDef = NbIn = NbOut = NbDyn = hasAQ = 0; + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if (!strcmp(bf->type, "field") || !strcmp(bf->type, "exposedField")) { + NbDef += 1; + } + if (!strcmp(bf->type, "eventIn") || !strcmp(bf->type, "exposedField")) { + NbIn += 1; + //check for anim + if (bf->hasAnim) NbDyn += 1; + } + if (!strcmp(bf->type, "eventOut") || !strcmp(bf->type, "exposedField")) { + NbOut += 1; + } + if (bf->hasAnim || bf->hasQuant) hasAQ = 1; + } + + n->hasAQInfo = hasAQ; + + //write the def2all table + if (NbDef) { + first = 1; + fprintf(f, "static const u16 %s_Def2All[] = { ", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if (strcmp(bf->type, "field") && strcmp(bf->type, "exposedField")) continue; + if (first) { + fprintf(f, "%d", i); + first = 0; + } else { + fprintf(f, ", %d", i); + } + } + fprintf(f, "};\n"); + } + //write the in2all table + if (NbIn) { + first = 1; + fprintf(f, "static const u16 %s_In2All[] = { ", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if (strcmp(bf->type, "eventIn") && strcmp(bf->type, "exposedField")) continue; + if (first) { + fprintf(f, "%d", i); + first = 0; + } else { + fprintf(f, ", %d", i); + } + } + fprintf(f, "};\n"); + } + //write the out2all table + if (NbOut) { + first = 1; + fprintf(f, "static const u16 %s_Out2All[] = { ", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if (strcmp(bf->type, "eventOut") && strcmp(bf->type, "exposedField")) continue; + if (first) { + fprintf(f, "%d", i); + first = 0; + } else { + fprintf(f, ", %d", i); + } + } + fprintf(f, "};\n"); + } + //then write the dyn2all table + if (NbDyn) { + first = 1; + fprintf(f, "static const u16 %s_Dyn2All[] = { ", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if (strcmp(bf->type, "eventIn") && strcmp(bf->type, "exposedField")) continue; + if (!bf->hasAnim) continue; + if (first) { + fprintf(f, "%d", i); + first = 0; + } else { + fprintf(f, ", %d", i); + } + } + fprintf(f, "};\n"); + } + + n->hasDef = NbDef; + n->hasDyn = NbDyn; + n->hasIn = NbIn; + n->hasOut = NbOut; + + + fprintf(f, "\nstatic u32 %s_get_field_count(GF_Node *node, u8 IndexMode)\n{\n", n->name); + fprintf(f, "\tswitch(IndexMode) {\n"); + + fprintf(f, "\tcase GF_SG_FIELD_CODING_IN: return %d;\n", NbIn); + fprintf(f, "\tcase GF_SG_FIELD_CODING_DEF: return %d;\n", NbDef); + fprintf(f, "\tcase GF_SG_FIELD_CODING_OUT: return %d;\n", NbOut); + fprintf(f, "\tcase GF_SG_FIELD_CODING_DYN: return %d;\n", NbDyn); + fprintf(f, "\tdefault:\n"); + fprintf(f, "\t\treturn %d;\n", gf_list_count(n->Fields)); + fprintf(f, "\t}"); + + fprintf(f, "\n}\n"); + + fprintf(f, "\nstatic GF_Err %s_get_field_index(GF_Node *n, u32 inField, u8 IndexMode, u32 *allField)\n{\n", n->name); + fprintf(f, "\tswitch(IndexMode) {\n"); + + if (NbIn) { + fprintf(f, "\tcase GF_SG_FIELD_CODING_IN:\n"); + fprintf(f, "\t\t*allField = %s_In2All[inField];\n\t\treturn GF_OK;\n", n->name); + } + if (NbDef) { + fprintf(f, "\tcase GF_SG_FIELD_CODING_DEF:\n"); + fprintf(f, "\t\t*allField = %s_Def2All[inField];\n\t\treturn GF_OK;\n", n->name); + } + if (NbOut) { + fprintf(f, "\tcase GF_SG_FIELD_CODING_OUT:\n"); + fprintf(f, "\t\t*allField = %s_Out2All[inField];\n\t\treturn GF_OK;\n", n->name); + } + if (NbDyn) { + fprintf(f, "\tcase GF_SG_FIELD_CODING_DYN:\n"); + fprintf(f, "\t\t*allField = %s_Dyn2All[inField];\n\t\treturn GF_OK;\n", n->name); + } + + fprintf(f, "\tdefault:\n"); + fprintf(f, "\t\treturn GF_BAD_PARAM;\n"); + fprintf(f, "\t}"); + + fprintf(f, "\n}\n"); + + + fprintf(f, "static GF_Err %s_get_field(GF_Node *node, GF_FieldInfo *info)\n{\n\tswitch (info->fieldIndex) {\n", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + + fprintf(f, "\tcase %d:\n", i); + + fprintf(f, "\t\tinfo->name = \"%s\";\n", (bf->name[0]=='_') ? bf->name+1 : bf->name); + + //skip all eventIn + if (!strcmp(bf->type, "eventIn")) { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_IN;\n"); + fprintf(f, "\t\tinfo->on_event_in = ((M_%s *)node)->on_%s;\n", n->name, bf->name); + } + else if (!strcmp(bf->type, "eventOut")) { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_OUT;\n"); + } + else if (!strcmp(bf->type, "field")) { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_FIELD;\n"); + } + else { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_EXPOSED_FIELD;\n"); + } + + if (strstr(bf->familly, "Node")) { + if (strstr(bf->familly, "MF")) { + fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_MFNODE;\n"); + } else { + fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_SFNODE;\n"); + } + //always remove the SF or MF, as all NDTs are SFXXX + fprintf(f, "\t\tinfo->NDTtype = NDT_SF%s;\n", bf->familly+2); + fprintf(f, "\t\tinfo->far_ptr = & ((M_%s *)node)->%s;\n", n->name, bf->name); + } else { + char szName[20]; + strcpy(szName, bf->familly); + strupr(szName); + //no ext type + fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_%s;\n", szName); + fprintf(f, "\t\tinfo->far_ptr = & ((M_%s *) node)->%s;\n", n->name, bf->name); + } + fprintf(f, "\t\treturn GF_OK;\n"); + } + fprintf(f, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n"); + + fprintf(f, "\nstatic s32 %s_get_field_index_by_name(char *name)\n{\n", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + fprintf(f, "\tif (!strcmp(\"%s\", name)) return %d;\n", (bf->name[0]=='_') ? bf->name+1 : bf->name, i); + } + fprintf(f, "\treturn -1;\n\t}\n"); +} + + +//write the Quantization info for each node field(Quant and BIFS-Anim info) +void WriteNodeQuant(FILE *f, BNode *n) +{ + u32 i; + BField *bf; + fprintf(f, "static Bool %s_get_aq_info(GF_Node *n, u32 FieldIndex, u8 *QType, u8 *AType, Fixed *b_min, Fixed *b_max, u32 *QT13_bits)\n{\n\tswitch (FieldIndex) {\n", n->name); + + for (i=0; iFields) ; i++ ) { + bf = gf_list_get(n->Fields, i); + if (!bf->hasAnim && !bf->hasQuant) continue; + + fprintf(f, "\tcase %d:\n", i); + //Anim Type + fprintf(f, "\t\t*AType = %d;\n", bf->AnimType); + //Quant Type + fprintf(f, "\t\t*QType = %s;\n", bf->quant_type); + if (!strcmp(bf->quant_type, "13")) + fprintf(f, "\t\t*QT13_bits = %s;\n", bf->qt13_bits); + + //Bounds + if (bf->hasBounds) { + if (!strcmp(bf->b_min, "+I") || !strcmp(bf->b_min, " +I") || !strcmp(bf->b_min, "I")) { + fprintf(f, "\t\t*b_min = FIX_MAX;\n"); + } else if (!strcmp(bf->b_min, "-I") || !strcmp(bf->b_min, "-65536")) { + fprintf(f, "\t\t*b_min = FIX_MIN;\n"); + } else { + fprintf(f, "\t\t*b_min = %s;\n", GetFixedPrintout(bf->b_min)); + } + if (!strcmp(bf->b_max, "+I") || !strcmp(bf->b_max, " +I") || !strcmp(bf->b_max, "I") || !strcmp(bf->b_max, "65535")) { + fprintf(f, "\t\t*b_max = FIX_MAX;\n"); + } else { + fprintf(f, "\t\t*b_max = %s;\n", GetFixedPrintout(bf->b_max)); + } + } + fprintf(f, "\t\treturn 1;\n"); + } + fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n"); +} + +void WriteNodeCode(GF_List *BNodes) +{ + FILE *f; + char token[20], tok[20]; + char *store; + u32 i, j, k, go; + BField *bf; + BNode *n; + + f = BeginFile("mpeg4_nodes", 1); + + fprintf(f, "#include \n\n"); + fprintf(f, "\n#include \n"); + + fprintf(f, "\n#ifndef GPAC_DISABLE_VRML\n"); + + + for (k=0; kskip_impl) continue; + + fprintf(f, "\n/*\n\t%s Node deletion\n*/\n\n", n->name); + fprintf(f, "static void %s_Del(GF_Node *node)\n{\n\tM_%s *p = (M_%s *) node;\n", n->name, n->name, n->name); + + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + //nothing on child events + if (!strcmp(bf->name, "addChildren")) continue; + if (!strcmp(bf->name, "removeChildren")) continue; + + //delete all children node + if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) { + is_parent = 1; + continue; + } + + //delete ALL fields that must be deleted: this includes eventIn and out since + //all fields are defined in the node + if (!strcmp(bf->familly, "MFInt") + || !strcmp(bf->familly, "MFFloat") + || !strcmp(bf->familly, "MFDouble") + || !strcmp(bf->familly, "MFBool") + || !strcmp(bf->familly, "MFInt32") + || !strcmp(bf->familly, "MFColor") + || !strcmp(bf->familly, "MFRotation") + || !strcmp(bf->familly, "MFString") + || !strcmp(bf->familly, "MFTime") + || !strcmp(bf->familly, "MFVec2f") + || !strcmp(bf->familly, "MFVec3f") + || !strcmp(bf->familly, "MFVec4f") + || !strcmp(bf->familly, "MFVec2d") + || !strcmp(bf->familly, "MFVec3d") + || !strcmp(bf->familly, "MFURL") + || !strcmp(bf->familly, "MFScript") + || !strcmp(bf->familly, "SFString") + || !strcmp(bf->familly, "SFURL") + || !strcmp(bf->familly, "SFImage") + ) { + char szName[500]; + strcpy(szName, bf->familly); + strlwr(szName); + fprintf(f, "\tgf_sg_%s_del(p->%s);\n", szName, bf->name); + } + else if (!strcmp(bf->familly, "SFCommandBuffer")) { + fprintf(f, "\tgf_sg_sfcommand_del(p->%s);\n", bf->name); + } + else if (strstr(bf->familly, "Node")) { + //this is a POINTER to a node + if (strstr(bf->familly, "SF")) { + fprintf(f, "\tgf_node_unregister((GF_Node *) p->%s, (GF_Node *) p);\t\n", bf->name); + } else { + //this is a POINTER to a chain + fprintf(f, "\tgf_node_unregister_children((GF_Node *) p, p->%s);\t\n", bf->name); + } + } + } + if (!strcmp(n->name, "CacheTexture")) { + fprintf(f, "\tif (p->data) gf_free(p->data);\n"); + } + if (is_parent) fprintf(f, "\tgf_sg_vrml_parent_destroy((GF_Node *) p);\t\n"); + fprintf(f, "\tgf_node_free((GF_Node *) p);\n}\n\n"); + + //node fields + WriteNodeFields(f, n); + WriteNodeQuant(f, n); + + // + // Constructor + // + + fprintf(f, "\n\nGF_Node *%s_Create()\n{\n\tM_%s *p;\n\tGF_SAFEALLOC(p, M_%s);\n", n->name, n->name, n->name); + fprintf(f, "\tif(!p) return NULL;\n"); + fprintf(f, "\tgf_node_setup((GF_Node *)p, TAG_MPEG4_%s);\n", n->name); + + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + //setup all children node + if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) { + fprintf(f, "\tgf_sg_vrml_parent_setup((GF_Node *) p);\n"); + break; + } + else if ( strstr(bf->familly, "Node") && strncmp(bf->type, "event", 5) ) { +#if 0 + //this is a POINTER to a node + if (strstr(bf->familly, "MF")) { + //this is a POINTER to a chain + fprintf(f, "\tp->%s = gf_list_new();\t\n", bf->name); + } +#endif + } + /*special case for SFCommandBuffer: we also create a command list*/ + if (!stricmp(bf->familly, "SFCommandBuffer")) { + fprintf(f, "\tp->%s.commandList = gf_list_new();\t\n", bf->name); + } + } + + //check if we have a child node + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if ( !strcmp(bf->name, "children") || + ( !strstr(bf->type, "event") && strstr(bf->familly, "MF") && strstr(bf->familly, "Node")) ) { + sprintf(n->Child_NDT_Name, "NDT_SF%s", bf->familly+2); + break; + } + } + + fprintf(f, "\n\t/*default field values*/\n"); + + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + + //nothing on eventIn or Out + if (!strcmp(bf->type, "eventIn")) continue; + if (!strcmp(bf->type, "eventOut")) continue; + + if (!strcmp(bf->def, "")) continue; + + //no default on nodes + if (strstr(bf->familly, "Node")) continue; + //extract default falue + + // + // SF Fields + // + + //SFBool + if (!strcmp(bf->familly, "SFBool")) { + if (!strcmp(bf->def, "1") || !strcmp(bf->def, "TRUE")) + fprintf(f, "\tp->%s = 1;\n", bf->name); + } + //SFFloat + else if (!strcmp(bf->familly, "SFFloat")) { + fprintf(f, "\tp->%s = %s;\n", bf->name, GetFixedPrintout(bf->def)); + } + //SFTime + else if (!strcmp(bf->familly, "SFTime")) { + fprintf(f, "\tp->%s = %s;\n", bf->name, bf->def); + } + //SFInt32 + else if (!strcmp(bf->familly, "SFInt32")) { + fprintf(f, "\tp->%s = %s;\n", bf->name, bf->def); + } + //SFURL + else if (!strcmp(bf->familly, "SFURL")) { + if (strcmp(bf->def, "NULL")) + fprintf(f, "\tp->%s = %s;\n", bf->name, bf->def); + } + //SFColor + else if (!strcmp(bf->familly, "SFColor")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + + fprintf(f, "\tp->%s.red = %s;\n", bf->name, GetFixedPrintout(token)); + GetNextToken(token, " "); + fprintf(f, "\tp->%s.green = %s;\n", bf->name, GetFixedPrintout(token)); + GetNextToken(token, " "); + fprintf(f, "\tp->%s.blue = %s;\n", bf->name, GetFixedPrintout(token)); + } + //SFVec2f + else if (!strcmp(bf->familly, "SFVec2f")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.x = %s;\n", bf->name, GetFixedPrintout(token)); + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.y = %s;\n", bf->name, GetFixedPrintout(token)); + } + //SFVec3f + else if (!strcmp(bf->familly, "SFVec3f")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.x = %s;\n", bf->name, GetFixedPrintout(token)); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.y = %s;\n", bf->name, GetFixedPrintout(token)); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.z = %s;\n", bf->name, GetFixedPrintout(token)); + } + //SFVec4f & SFRotation + else if (!strcmp(bf->familly, "SFVec4f") || !strcmp(bf->familly, "SFRotation")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.x = %s;\n", bf->name, GetFixedPrintout(token)); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.y = %s;\n", bf->name, GetFixedPrintout(token)); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.z = %s;\n", bf->name, GetFixedPrintout(token)); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(f, "\tp->%s.q = %s;\n", bf->name, GetFixedPrintout(token)); + } + //SFString + else if (!strcmp(bf->familly, "SFString")) { + fprintf(f, "\tp->%s.buffer = (char*)gf_malloc(sizeof(char) * %d);\n", bf->name, strlen(bf->def)+1); + fprintf(f, "\tstrcpy(p->%s.buffer, \"%s\");\n", bf->name, bf->def); + } + + // + // MF Fields + // + //MFFloat + else if (!strcmp(bf->familly, "MFFloat")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, " ,")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (SFFloat*)gf_malloc(sizeof(SFFloat)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, " ,")) go = 0; + TranslateToken(token); + fprintf(f, "\tp->%s.vals[%d] = %s;\n", bf->name, j, GetFixedPrintout(token)); + j+=1; + } + } + //MFVec2f + else if (!strcmp(bf->familly, "MFVec2f")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (SFVec2f*)gf_malloc(sizeof(SFVec2f)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].x = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].y = %s;\n", bf->name, j, GetFixedPrintout(tok)); + j+=1; + CurrentLine = store; + } + } + //MFVec3f + else if (!strcmp(bf->familly, "MFVec3f")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (SFVec3f *)gf_malloc(sizeof(SFVec3f)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].x = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].y = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].z = %s;\n", bf->name, j, GetFixedPrintout(tok)); + j+=1; + CurrentLine = store; + } + } + //MFVec4f + else if (!strcmp(bf->familly, "MFVec4f") || !strcmp(bf->familly, "MFRotation")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (GF_Vec4*)gf_malloc(sizeof(GF_Vec4)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].x = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].y = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].z = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d].q = %s;\n", bf->name, j, GetFixedPrintout(tok)); + j+=1; + CurrentLine = store; + } + } + //MFInt32 + else if (!strcmp(bf->familly, "MFInt32")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (SFInt32*)gf_malloc(sizeof(SFInt32)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + fprintf(f, "\tp->%s.vals[%d] = %s;\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFColor + else if (!strcmp(bf->familly, "MFColor")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (SFColor*)gf_malloc(sizeof(SFColor)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + fprintf(f, "\tp->%s.vals[%d].red = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + fprintf(f, "\tp->%s.vals[%d].green = %s;\n", bf->name, j, GetFixedPrintout(tok)); + GetNextToken(tok, " "); + fprintf(f, "\tp->%s.vals[%d].blue = %s;\n", bf->name, j, GetFixedPrintout(tok)); + j+=1; + CurrentLine = store; + } + } + //MFString + else if (!strcmp(bf->familly, "MFString")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (char**)gf_malloc(sizeof(SFString)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " \""); + fprintf(f, "\tp->%s.vals[%d] = (char*)gf_malloc(sizeof(char) * %d);\n", bf->name, j, strlen(tok)+1); + fprintf(f, "\tstrcpy(p->%s.vals[%d], \"%s\");\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFTime + else if (!strcmp(bf->familly, "MFTime")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(f, "\tp->%s.vals = (SFTime*)gf_malloc(sizeof(SFTime)*%d);\n", bf->name, j); + fprintf(f, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " \""); + TranslateToken(tok); + fprintf(f, "\tp->%s.vals[%d] = %s;\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + + //other nodes + else if (!strcmp(bf->familly, "SFImage")) { + //we currently only have SFImage, with NO texture so do nothing + } + //unknown init (for debug) + else { + fprintf(f, "UNKNOWN FIELD (%s);\n", bf->familly); + + } + } + fprintf(f, "\treturn (GF_Node *)p;\n}\n\n"); + + } + + fprintf(f, "\n\n\n"); + + //creator function + fprintf(f, "GF_Node *gf_sg_mpeg4_node_new(u32 NodeTag)\n{\n\tswitch (NodeTag) {\n"); + for (i=0; iskip_impl) { + fprintf(f, "\tcase TAG_MPEG4_%s:\n\t\treturn %s_Create();\n", n->name, n->name); + } + } + fprintf(f, "\tdefault:\n\t\treturn NULL;\n\t}\n}\n\n"); + + fprintf(f, "const char *gf_sg_mpeg4_node_get_class_name(u32 NodeTag)\n{\n\tswitch (NodeTag) {\n"); + for (i=0; iskip_impl) fprintf(f, "\tcase TAG_MPEG4_%s:\n\t\treturn \"%s\";\n", n->name, n->name); + } + fprintf(f, "\tdefault:\n\t\treturn \"Unknown Node\";\n\t}\n}\n\n"); + + fprintf(f, "void gf_sg_mpeg4_node_del(GF_Node *node)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) { + fprintf(f, "\tcase TAG_MPEG4_%s:\n\t\t%s_Del(node); return;\n", n->name, n->name); + } + } + fprintf(f, "\tdefault:\n\t\treturn;\n\t}\n}\n\n"); + + fprintf(f, "u32 gf_sg_mpeg4_node_get_field_count(GF_Node *node, u8 code_mode)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) { + fprintf(f, "\tcase TAG_MPEG4_%s:return %s_get_field_count(node, code_mode);\n", n->name, n->name); + } + } + fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n"); + + fprintf(f, "GF_Err gf_sg_mpeg4_node_get_field(GF_Node *node, GF_FieldInfo *field)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) { + fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_field(node, field);\n", n->name, n->name); + } + } + fprintf(f, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n"); + + fprintf(f, "GF_Err gf_sg_mpeg4_node_get_field_index(GF_Node *node, u32 inField, u8 code_mode, u32 *fieldIndex)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) { + fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_field_index(node, inField, code_mode, fieldIndex);\n", n->name, n->name); + } + } + fprintf(f, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n"); + + fprintf(f, "Bool gf_sg_mpeg4_node_get_aq_info(GF_Node *node, u32 FieldIndex, u8 *QType, u8 *AType, Fixed *b_min, Fixed *b_max, u32 *QT13_bits)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) { + fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_aq_info(node, FieldIndex, QType, AType, b_min, b_max, QT13_bits);\n", n->name, n->name); + } + } + fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n"); + + fprintf(f, "u32 gf_sg_mpeg4_node_get_child_ndt(GF_Node *node)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl && strlen(n->Child_NDT_Name) ) { + fprintf(f, "\tcase TAG_MPEG4_%s: return %s;\n", n->name, n->Child_NDT_Name); + } + } + fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n"); + + + fprintf(f, "\nu32 gf_node_mpeg4_type_by_class_name(const char *node_name)\n{\n\tif(!node_name) return 0;\n"); + for (i=0; iskip_impl) continue; + fprintf(f, "\tif (!strcmp(node_name, \"%s\")) return TAG_MPEG4_%s;\n", n->name, n->name); + } + fprintf(f, "\treturn 0;\n}\n\n"); + + fprintf(f, "s32 gf_sg_mpeg4_node_get_field_index_by_name(GF_Node *node, char *name)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) { + fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_field_index_by_name(name);\n", n->name, n->name); + } + } + fprintf(f, "\tdefault:\n\t\treturn -1;\n\t}\n}\n\n"); + + fprintf(f, "\n#endif /*GPAC_DISABLE_VRML*/\n"); + + EndFile(f, "", 1); +} + +void ParseTemplateFile(FILE *nodes, GF_List *BNodes, GF_List *NDTs, u32 version) +{ + char sLine[2000]; + char token[100]; + char *p; + BNode *n; + BField *f; + u32 j, i, k; + + //get lines one by one + n = NULL; + while (!feof(nodes)) { + fgets(sLine, 2000, nodes); + //skip comment and empty lines + if (sLine[0] == '#') continue; + if (sLine[0] == '\n') continue; + + CurrentLine = sLine; + + //parse the line till end of line + while (GetNextToken(token, " \t")) { + + //this is a new node + if (!strcmp(token, "PROTO") ) { + n = BlankNode(); + n->version = version; + gf_list_add(BNodes, n); + + //get its name + GetNextToken(n->name, " \t["); + if (!strcmp(n->name, "TimeSensor")) { + n = n; + } + + //extract the NDTs + GetNextToken(token, "\t[ %#="); + if (strcmp(token, "NDT")) { + printf("Corrupted template file\n"); + return; + } + while (1) { + GetNextToken(token, "=, \t"); + //done with NDTs + if (token[0] == '%') break; + + //update the NDT list + CheckInTable(token, NDTs); + p = gf_malloc(strlen(token)+1); + strcpy(p, token); + gf_list_add(n->NDT, p); + } + + //extract the coding type + if (strcmp(token, "%COD")) { + printf("Corrupted template file\n"); + return; + } else { + GetNextToken(token, "= "); + if (token[0] == 'N') { + n->codingType = 0; + } else { + n->codingType = 1; + } + } + } + //this is NOT a field + else if (token[0] == ']' || token[0] == '{' || token[0] == '}' ) { + break; + } + //parse a field + else { + if (!n) { + printf("Corrupted template file\n"); + return; + } + f = BlankField(); + gf_list_add(n->Fields, f); + + //get the field type + strcpy(f->type, token); + GetNextToken(f->familly, " \t"); + GetNextToken(f->name, " \t"); + //fix for our own code :( + if (!strcmp(f->name, "tag")) strcpy(f->name, "_tag"); + if (!strcmp(f->name, "auto")) strcpy(f->name, "_auto"); + + //has default + skip_sep(" \t"); + if (GetNextToken(token, "#\t")) { + j=0; + while (token[j] == ' ') j+=1; + if (token[j] == '[') j+=1; + if (token[j] == '"') j+=1; + + if (token[j] != '"' && token[j] != ']') { + strcpy(f->def, token+j); + j=1; + while (j) { + switch (f->def[strlen(f->def)-1]) { + case ' ': + case '"': + case ']': + f->def[strlen(f->def)-1] = 0; + break; + default: + j=0; + break; + } + } + } else { + strcpy(f->def, ""); + } + if (!strcmp(f->familly, "SFFloat")) { + if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) { + strcpy(f->def, "FIX_MAX"); + } else if (!strcmp(f->def, "-I")) { + strcpy(f->def, "FIX_MIN"); + } + } else if (!strcmp(f->familly, "SFTime")) { + if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) { + strcpy(f->def, "FIX_MAX"); + } else if (!strcmp(f->def, "-I")) { + strcpy(f->def, "FIX_MIN"); + } + } else if (!strcmp(f->familly, "SFInt32")) { + if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) { + strcpy(f->def, "1 << 31"); + } else if (!strcmp(f->def, "-I")) { + strcpy(f->def, "- (1 << 31)"); + } + } + } + //has other + while (GetNextToken(token, " \t#%=")) { + switch (token[0]) { + //bounds + case 'b': + f->hasBounds = 1; + GetNextToken(f->b_min, "[(,"); + GetNextToken(f->b_max, ")]"); + break; + case 'q': + f->hasQuant = 1; + GetNextToken(f->quant_type, " \t"); + if (!strcmp(f->quant_type, "13")) + GetNextToken(f->qt13_bits, " \t"); + break; + case 'a': + f->hasAnim = 1; + GetNextToken(token, " \t"); + f->AnimType = atoi(token); + break; + default: + break; + } + } + } + } + } + + + for (k=0; kFields); i++) { + f = gf_list_get(n->Fields, i); + //nothing on events + if (!strcmp(f->type, "eventIn")) continue; + if (!strcmp(f->type, "eventOut")) continue; + if (!strcmp(f->def, "")) continue; + if (strstr(f->familly, "Node")) continue; + n->hasDefault = 1; + } + } +} + + +void WriteNodeDump(FILE *f, BNode *n) +{ + BField *bf; + u32 i; + + fprintf(f, "static const char *%s_FieldName[] = {\n", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if (!i) { + fprintf(f, " \"%s\"", bf->name); + } else { + fprintf(f, ", \"%s\"", bf->name); + } + } + fprintf(f, "\n};\n\n"); +} + +void parse_profile(GF_List *nodes, FILE *prof) +{ + char sLine[2000]; + BNode *n; + Bool found; + u32 i; + + while (!feof(prof)) { + fgets(sLine, 2000, prof); + //skip comment and empty lines + if (sLine[0] == '#') continue; + if (sLine[0] == '\n') continue; + if (strstr(sLine, "Proximity")) + found = 0; + found = 1; + while (found) { + switch (sLine[strlen(sLine)-1]) { + case '\n': + case '\r': + case ' ': + sLine[strlen(sLine)-1] = 0; + break; + default: + found = 0; + break; + } + } + +// if (0 && !stricmp(sLine, "Appearance") || !stricmp(sLine, "Shape") || !stricmp(sLine, "Sound2D") ) { + if (0) { + printf("Warning: cannot disable node %s (required in all BIFS profiles)\n", sLine); + } else { + found = 0; + for (i=0; iname, sLine)) { + n->skip_impl = 1; + found = 1; + break; + } + } + if (!found) printf("cannot disable %s: node not found\n", sLine); + } + } +} + +char *format_bit_string(char *str, u32 val, u32 nb_bits) +{ + u32 i, len; + strcpy(str, ""); + while (nb_bits) { + strcat(str, (val%2) ? "1" : "0"); + val>>=1; + nb_bits--; + } + len = strlen(str); + for (i=0; i ((1<\n"\ + "\n"\ + "\n"\ + "NdtListV%d.html\n"\ + "\n"\ + "\n"\ + "Node Coding Tables for BIFS Version %d group\n" + ,GPAC_FULL_VERSION, i+1, i+1); + + for (j=0; jversion != i+1) continue; + if (!IsNodeInTable(n, ndt)) continue; + nb_in_ndt ++; + } + + if (!nb_in_ndt) continue; + + fprintf(f, "
\n"\ + "\n"\ + "\n"\ + "\n", ndt, ndt, nb_in_ndt); + + nb_bits = GetBitsCount(nb_in_ndt); + fprintf(f, "\n", format_bit_string(szStr, 0, nb_bits)); + + idx = 1; + for (k=0; kversion != i+1) continue; + if (!IsNodeInTable(n, ndt)) continue; + + + n->hasDef = n->hasIn = n->hasOut = n->hasDyn = 0; + for (l=0; lFields); l++) { + BField *bf = gf_list_get(n->Fields, l); + if (!strcmp(bf->type, "field") || !strcmp(bf->type, "exposedField")) { + n->hasDef += 1; + } + if (!strcmp(bf->type, "eventIn") || !strcmp(bf->type, "exposedField")) { + n->hasIn += 1; + //check for anim + if (bf->hasAnim) n->hasDyn += 1; + } + if (!strcmp(bf->type, "eventOut") || !strcmp(bf->type, "exposedField")) { + n->hasOut += 1; + } + } + + fprintf(f, "\n", n->name, format_bit_string(szStr, idx, nb_bits), get_nb_bits(n->hasDef), get_nb_bits(n->hasIn), get_nb_bits(n->hasOut), get_nb_bits(n->hasDyn)); + idx++; + } + + fprintf(f, "
%s%u nodes
reserved

%s

 

 

 

 

%s

%s

%d DEF bits

%d IN bits

%d OUT bits

%d DYN bits

\n"); + } + gf_fclose(f); + } + +} + +int main (int argc, char **argv) +{ + Bool generate_ndt = 0; + char szTempFile[1024]; + FILE *nodes, *ndt_c, *ndt_h, *fskip; + GF_List *BNodes, *NDTs; + u32 i, j, nbVersion; + BNode *n; + BField *bf; + + if (argc < 1) { + PrintUsage(); + return 0; + } + + BNodes = gf_list_new(); + NDTs = gf_list_new(); + + + + fskip = NULL; + if (argc>1) { + i=1; + if (!strcmp(argv[i], "-ndt")) { + generate_ndt = 1; + } else if (argv[i][0]=='-') { + fskip = gf_fopen(argv[i+1], "rt"); + if (!fskip) { + printf("file %s not found\n", argv[i+1]); + return 0; + } + i+=2; + } + } + nbVersion=1; + while (1) { + sprintf(szTempFile, "templates%u.txt", nbVersion); + nodes = gf_fopen(szTempFile, "rt"); + if (!nodes) { + sprintf(szTempFile, "template%u.txt", nbVersion); + nodes = gf_fopen(szTempFile, "rt"); + } + if (!nodes) break; + + //all nodes are in the same list but we keep version info + ParseTemplateFile(nodes, BNodes, NDTs, nbVersion); + + + //special case for viewport: it is present in V1 but empty + if (nbVersion==1) CheckInTable("SFViewportNode", NDTs); + nbVersion++; + gf_fclose(nodes); + } + nbVersion--; + printf("BIFS tables parsed: %d versions\n", nbVersion); + + if (generate_ndt) { + generate_ndts(NDTs, BNodes, nbVersion); + goto exit; + } + + if (fskip) { + parse_profile(BNodes, fskip); + gf_fclose(fskip); + } + + //write the nodes def + WriteNodesFile(BNodes, NDTs, nbVersion); + //write all nodes init stuff + WriteNodeCode(BNodes); + + //write all NDTs + ndt_h = BeginFile("NDT", 0); + ndt_c = BeginFile("NDT", 1); + + fprintf(ndt_h, "#include \n\n"); + fprintf(ndt_h, "\n\n#ifndef GPAC_DISABLE_BIFS\n"); + + fprintf(ndt_c, "\n\n#include \n"); + fprintf(ndt_c, "\n\n#ifndef GPAC_DISABLE_BIFS\n"); + + //prepare the encoding file + fprintf(ndt_h, "\n\nu32 ALL_GetNodeType(const u32 *table, const u32 count, u32 NodeTag, u32 Version);\n\n"); + fprintf(ndt_c, "\n\nu32 ALL_GetNodeType(const u32 *table, const u32 count, u32 NodeTag, u32 Version)\n{\n\tu32 i = 0;"); + fprintf(ndt_c, "\n\twhile (iskip_impl) continue; + for (j=0; jFields); j++) { + bf = gf_list_get(n->Fields, j); + if (!strcmp(bf->name, "children")) { + fprintf(ndt_c, "\tcase TAG_MPEG4_%s:\n\t\treturn NDT_SF%s;\n", n->name, bf->familly+2); + break; + } + } + } + fprintf(ndt_c, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n"); + fprintf(ndt_c, "\n\n#endif /*GPAC_DISABLE_BIFS*/\n\n"); + + fprintf(ndt_h, "\n\n#endif /*GPAC_DISABLE_BIFS*/\n\n"); + EndFile(ndt_h, "NDT", 0); + EndFile(ndt_c, "", 1); + + +exit: + //free NDTs + while (gf_list_count(NDTs)) { + char *tmp = gf_list_get(NDTs, 0); + gf_free(tmp); + gf_list_rem(NDTs, 0); + } + gf_list_del(NDTs); + //free nodes + while (gf_list_count(BNodes)) { + n = gf_list_get(BNodes, 0); + gf_list_rem(BNodes, 0); + while (gf_list_count(n->NDT)) { + char *tmp = gf_list_get(n->NDT, 0); + gf_free(tmp); + gf_list_rem(n->NDT, 0); + } + gf_list_del(n->NDT); + while (gf_list_count(n->Fields)) { + bf = gf_list_get(n->Fields, 0); + gf_free(bf); + gf_list_rem(n->Fields, 0); + } + gf_list_del(n->Fields); + gf_free(n); + } + gf_list_del(BNodes); + + return 0; +} + diff --git a/applications/generators/MPEG4/skip.txt b/applications/generators/MPEG4/skip.txt new file mode 100644 index 0000000..b064f06 --- /dev/null +++ b/applications/generators/MPEG4/skip.txt @@ -0,0 +1,181 @@ +#MPEG-4 v1.0 + +#Anchor +#AnimationStream +#AudioBuffer +#AudioClip +#AudioDelay +#AudioFX +#AudioMix +#AudioSource +#AudioSwitch +#Background2D +#Bitmap +#Circle +#Curve2D +#Background +#Billboard +#Box +#Color +#ColorInterpolator +#Collision +#CompositeTexture2D +#CompositeTexture3D +#Conditional +#Cone +#Coordinate2D +#Coordinate +#CoordinateInterpolator2D +#CoordinateInterpolator +#Cylinder +#CylinderSensor +#DirectionalLight +#DiscSensor +#ElevationGrid +Expression +#Extrusion +Face +FaceDefMesh +FaceDefTables +FaceDefTransform +FAP +FDP +FIT +#Fog +#FontStyle +#Form +#Group +#ImageTexture +#IndexedFaceSet +#IndexedFaceSet2D +#IndexedLineSet +#IndexedLineSet2D +#Inline +#LOD +#Layer2D +#Layer3D +#Layout +#LineProperties +#ListeningPoint +#Material2D +#Material +#MovieTexture +#NavigationInfo +#Normal +#NormalInterpolator +#OrderedGroup +#OrientationInterpolator +#PointLight +#PointSet +#PointSet2D +#PixelTexture +#PlaneSensor2D +#PlaneSensor +#PositionInterpolator2D +#PositionInterpolator +#ProximitySensor2D +#ProximitySensor +#QuantizationParameter +#Rectangle +#ScalarInterpolator +#Script +#Sound +#Sphere +#SphereSensor +#SpotLight +#Switch +#TermCap +#TextureCoordinate +#TextureTransform +#Text +#TimeSensor +#TouchSensor +#Transform2D +#Transform +#Valuator +#Viewpoint +#VisibilitySensor +Viseme +#WorldInfo + + +#MPEG-4 v2.0 +#AcousticMaterial +#AcousticScene +#ApplicationWindow +BAP +BDP +Body +BodyDefTable +BodySegmentConnectionHint +#DirectiveSound +#Hierarchical3DMesh +#MaterialKey +#PerceptualParameters + +#MPEG-4 v3.0 +#TemporalTransform +#TemporalGroup +#ServerCommand + +#MPEG-4 v4.0 +#InputSensor +#MatteTexture +#MediaBuffer +#MediaControl +#MediaSensor + +#MPEG-4 V5 +BitWrapper +#CoordinateInterpolator4D +DepthImage +FFD +Implicit +XXLFM_Appearance +XXLFM_BlendList +XXLFM_FrameList +XXLFM_LightMap +XXLFM_SurfaceMapList +XXLFM_ViewMapList +MeshGrid +#NonLinearDeformer +NurbsCurve +NurbsCurve2D +NurbsSurface +OctreeImage +XXParticles +XXParticleInitBox +XXPlanarObstacle +XXPointAttractor +PointTexture +#PositionAnimator +#PositionAnimator2D +#PositionInterpolator4D +ProceduralTexture +Quadric +SBBone +SBMuscle +SBSegment +SBSite +SBSkinnedModel +SBVCAnimation +#ScalarAnimator +SimpleTexture +SolidRep +SubdivisionSurface +SubdivSurfaceSector +WaveletSubdivisionSurface + +#MPEG-4 V6 +#Clipper2D +#ColorTransform +#Ellipse +#LinearGradient +#PathLayout +#RadialGradient +SynthesizedTexture +#TransformMatrix2D +#Viewport +#XCurve2D +#XFontStyle +#XLineProperties diff --git a/applications/generators/MPEG4/templates1.txt b/applications/generators/MPEG4/templates1.txt new file mode 100644 index 0000000..a64c34e --- /dev/null +++ b/applications/generators/MPEG4/templates1.txt @@ -0,0 +1,1292 @@ +#-- Version 1 --# +# templates for the BIFS nodes +# ============================= +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 Reserved +# +# %a=y Animation method for fields that can be animated +# +## OO 081498 To match BIFS's update numbering +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying which node sub +# types the node belongs to. Moreover, each field of type SF/MF3DNode is re assigned +# a unique correct NodeDataType according to specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# Jan 16, 2003 (MBS) AudioBuffer.length changed to exposedField +# Dec 10, 1997 (Yuval Fisher) SFTimerNode changed to SFTimeSensorNode +# Dec 10, 1997 (Yuval Fisher) SFFitNode changed to SFFITNode +# Dec 10, 1997 (Yuval Fisher) children in Form changed to exposedField +# Dec 11, 1997 (Yuval Fisher) exposedfield changed to exposedField in Form +# +# Dec 19, 1997 (Yuval Fisher - Following Alexandros' Parser errors) +# - FALSE removed from isActive field on AudioClip node +# - %b=(-I,+I) removed from set_fraction on ColorInterpolator +# - justify field value in FontStyle enclosed in [] +# - %b=(-I,+I) removed from set_fraction on ScalarInterpolator +# - removed -1 from duration_changed and FALSE from isActive in VideoObject2D +# - changed renderedFace to exposedField in Face node +# - changed renderedFace to exposedField in Body node -- just temporary anyway +# - animation type on height field of elevation grid changed from 11 to 7 +# - vector field of Normal node, transposed quantization=9 and animation=4 +# - changed eventIn to exposedField in background, fog, navigationInfo,viewpoint +# of Layer3D +# - Same as above for Composite3DTexture +# +# Dec 22, 1997 (Yuval Fisher) added Conditional back. +# March 16: +# Reordered alphabetically +# Sound field spatialize changed to exposedfield +# Sound added addChildren and deleteChildren to all nodes with children +# Changed children2D field to be children in CompositeMap +# Eliminate ucs_2 field from StreamingText +# Do the childrenLayer fields need add and remove eventIns ? +# sound field changed to source in Sound2D +# +# March 24 +# Many changes based on changes adopted in Tokyo +# added bounding boxes to Layer2D and Layer3D +# +# March 25 +# Added Animation to various nodes - Checked template with Julien. +# +# March 30 +# 0 -> FALSE and MFURL:null->[] corrections. +# +# April 13 +# Added TermCap per Joern +# +# May 12 +# add and remove ChildrenLayer in Layer3d was missing 'Layer' +# term cap had int instead of int32 +# +# May 19 +# DiscSensor center had a wrong quantization type +# May 26 +# drawOrderMin and Max were SFVec3f in Quantization Parameter +# June 8 +# Layer2D,3D Has an SFInt32 depth, converted to SFFloat +# Text should hav an MFString +# June 16 +# added to PlaneSensor: +#eventOut SFVec3f translation_changed +# +# +# to do: +# check if SFstring or SFBuffer ins AudioFX +# check children field for AudioSource +# fix FIT node bounds +# ask Eric if Face really has a URL -- try to eliminate it because it's an +# animation stream/can bounds be put on the faceDefMesh parameters why are +# these fields +# +# Oct 28 +# JS: Updated all template to correct DOC +# JCD updated Form, Layout and Valuator +# JS: To check FBA latest nodes +# November 2, 1998 (Mikael Bourges-Sevenier) AudioBuffer has MFAudioNode children not MFNode +# November 2, 1998 (Mikael Bourges-Sevenier) Face node is a SF3DNode also. +# November 2, 1998 (Mikael Bourges-Sevenier) modif I bound -> +I bound +# November 2, 1998 (Mikael Bourges-Sevenier) modif xFInt -> xFInt32 where missing +# November 2, 1998 (Mikael Bourges-Sevenier) removed childrenLayer in Layer2D +# Nov 2: JS: Integrated latest comments from Gabriel and Liam +# Nov 3: Still more bug corrections! The last ones? Added also type correspondance for +# semantic tables. +# JS: Changesd all fap values to be 0 by default +# Feb 9 99: Changed Layer2D/3D to be SF3DNode, suppresed cone anim stuff +# +# Mar 1 1999 +# group -> groups in Form plus other minor fixes +# Mar 8, 1999 +# Add speed to AudioSource +# June 15, 1999 YF +# Changed renderedFace to default [] from NULL & removed blank line +# +# Dec 20, 1999 YF +# FABs get default value of +I +# +# Aug 10, 2000 YF per Steve Woods: +# VisibilitySensor %b= missing from center and size fields +# +# July 10, 2001 YF per DCOR1 +# modify maxAngle, minAngle and diskAngle in CylinderSensor +# minAngle in DiscSensor changed to 0 +# +# Jan 2, 2002 YF per decision at meeting +# revert to capilized letter of factor, offset, sum in Valuator +# +# Aug 13, 2002 -- added activate field to Anchor per COR2 item +# modified field to exposedField in FontStyle per COR2 +# + +PROTO Anchor [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFString description "" +exposedField MFString parameter [] +exposedField MFURL url [] +eventIn SFBool activate +]{ +} + + +PROTO AnimationStream [ #%NDT=SFWorldNode,SF3DNode,SF2DNode,SFStreamingNode %COD=N +exposedField SFBool loop FALSE +exposedField SFFloat speed 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFTime startTime 0 #%b=(-I,+I) +exposedField SFTime stopTime 0 #%b=(-I,+I) +exposedField MFURL url [] +eventOut SFTime duration_changed +eventOut SFBool isActive +] { +} + + +PROTO Appearance [ #%NDT=SFWorldNode,SFAppearanceNode %COD=N +exposedField SFMaterialNode material NULL +exposedField SFTextureNode texture NULL +exposedField SFTextureTransformNode textureTransform NULL +] { +} + +PROTO AudioBuffer [ #%NDT=SFWorldNode,SFAudioNode %COD=N +exposedField SFBool loop FALSE +exposedField SFFloat pitch 1 #%b=[0,+I) #%q=0 #%a=7 +exposedField SFTime startTime 0 #%b=[0,+I) #%q=0 +exposedField SFTime stopTime 0 #%b=[0,+I) #%q=0 +exposedField MFAudioNode children [] +exposedField SFInt32 numChan 1 #%b=[0,255] #%q=13 8 +exposedField MFInt32 phaseGroup [1] +exposedField SFFloat length 0.0 #%b=[0,+I) #%q=0 +eventOut SFTime duration_changed +eventOut SFBool isActive +] { +} + +PROTO AudioClip [ #%NDT=SFWorldNode,SFAudioNode,SFStreamingNode %COD=N +exposedField SFString description "" +exposedField SFBool loop FALSE +exposedField SFFloat pitch 1.0 #%b=[0,+I) #%q=0 #%a=7 +exposedField SFTime startTime 0 #%b=(-I,+I) +exposedField SFTime stopTime 0 #%b=(-I,+I) +exposedField MFURL url [] +eventOut SFTime duration_changed +eventOut SFBool isActive +] { +} + +PROTO AudioDelay [ #%NDT=SFWorldNode,SFAudioNode %COD=N +eventIn MFAudioNode addChildren +eventIn MFAudioNode removeChildren +exposedField MFAudioNode children [] +exposedField SFTime delay 0 #%b=[0,+I) +field SFInt32 numChan 1 #%b=[0,255] #%q=13 8 +field MFInt32 phaseGroup [] #%b=[0,255] #%q=13 8 +] { +} + +PROTO AudioFX [ #%NDT=SFWorldNode,SFAudioNode %COD=N +eventIn MFAudioNode addChildren +eventIn MFAudioNode removeChildren +exposedField MFAudioNode children [] +exposedField SFString orch "" +exposedField SFString score "" +exposedField MFFloat params [] #%b=(-I,+I) #%q=0 #%a=7 +field SFInt32 numChan 1 #%b=[0,255] #%q=13 8 +field MFInt32 phaseGroup [] #%b=[0,255] #%q=13 8 +] { +} + +PROTO AudioMix [ #%NDT=SFWorldNode,SFAudioNode %COD=N +eventIn MFAudioNode addChildren +eventIn MFAudioNode removeChildren +exposedField MFAudioNode children [] +exposedField SFInt32 numInputs 1 #%b=[1,255] #%q=13 8 +exposedField MFFloat matrix [] #%b=[0,1] #%q=0 #%a=7 +field SFInt32 numChan 1 #%b=[0,255] #%q=13 8 +field MFInt32 phaseGroup [] #%b=[0,255] #%q=13 8 +] { +} + +PROTO AudioSource [ #%NDT=SFWorldNode,SFAudioNode,SFStreamingNode %COD=N +eventIn MFAudioNode addChildren +eventIn MFAudioNode removeChildren +exposedField MFAudioNode children [] +exposedField MFURL url [] +exposedField SFFloat pitch 1 #%b=[0,+I) #%q=0 #%a=7 +exposedField SFFloat speed 1 #%b=[0,+I) #%q=0 #%a=7 +exposedField SFTime startTime 0 +exposedField SFTime stopTime 0 +field SFInt32 numChan 1 #%b=[0,255] #%q=13 8 +field MFInt32 phaseGroup [] #%b=[0,255] #%q=13 8 +] { +} + +PROTO AudioSwitch [ #%NDT=SFWorldNode,SFAudioNode %COD=N +eventIn MFAudioNode addChildren +eventIn MFAudioNode removeChildren +exposedField MFAudioNode children [] +exposedField MFInt32 whichChoice [] #%b=[0,1] #%q=13 1 +field SFInt32 numChan 1 #%b=[0,255] #%q=13 8 +field MFInt32 phaseGroup [] #%b=[0,255] #%q=13 8 +] { +} + +PROTO Background [ #%NDT=SFWorldNode,SF3DNode,SFBackground3DNode %COD=N +eventIn SFBool set_bind +exposedField MFFloat groundAngle [] #%b=[0,1.5707963] #%q=6 #%a=8 +exposedField MFColor groundColor [] #%b=[0,1] #%q=4 #%a=4 +exposedField MFURL backUrl [] +exposedField MFURL bottomUrl [] +exposedField MFURL frontUrl [] +exposedField MFURL leftUrl [] +exposedField MFURL rightUrl [] +exposedField MFURL topUrl [] +exposedField MFFloat skyAngle [] #%b=[0,3.14159265] #%q=6 #%a=8 +exposedField MFColor skyColor [ 0 0 0 ] #%b=[0,1] #%q=4 #%a=4 +eventOut SFBool isBound +] { +} + +PROTO Background2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode,SFBackground2DNode %COD=N +eventIn SFBool set_bind +exposedField SFColor backColor 0 0 0 #%b=[0,1] #%q=4 #%a=4 +exposedField MFURL url [] +eventOut SFBool isBound +] { +} + +PROTO Billboard [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFVec3f axisOfRotation 0 1 0 #%q=9 #%a=9 +] { +} + +# modified JCD +PROTO Bitmap [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFVec2f scale -1 -1 #%b=[-1,+I) #%q=12 #%a=12 +] { +} + + +PROTO Box [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +field SFVec3f size 2 2 2 #%b=[0,+I) #%q=11 +] { +} + +PROTO Circle [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFFloat radius 1 #%b=[0,+I) #%q=12 #%a=7 +] { +} + +PROTO Collision [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFBool collide TRUE +field SF3DNode proxy NULL +eventOut SFTime collideTime +] { +} + +PROTO Color [ #%NDT=SFWorldNode,SFColorNode %COD=N +exposedField MFColor color [] #%b=[0,1] #%q=4 #%a=4 +] { +} + +PROTO ColorInterpolator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFColor keyValue [] #%b=[0,1] #%q=4 +eventOut SFColor value_changed +] { +} + +PROTO CompositeTexture2D [ #%NDT=SFWorldNode,SFTextureNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFInt32 pixelWidth -1 #%b=[0,65535] #%q=13 16 +exposedField SFInt32 pixelHeight -1 #%b=[0,65535] #%q=13 16 +exposedField SFBackground2DNode background NULL +exposedField SFViewportNode viewport NULL +field SFInt32 repeatSandT 3 #%b=[0,3] #%q=13 2 +] { +} + +PROTO CompositeTexture3D [ #%NDT=SFWorldNode,SFTextureNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFInt32 pixelWidth -1 #%b=[0,65535] #%q=13 16 +exposedField SFInt32 pixelHeight -1 #%b=[0,65535] #%q=13 16 +exposedField SFBackground3DNode background NULL +exposedField SFFogNode fog NULL +exposedField SFNavigationInfoNode navigationInfo NULL +exposedField SFViewpointNode viewpoint NULL +field SFBool repeatS TRUE +field SFBool repeatT TRUE +] { +} + + +PROTO Conditional [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +eventIn SFBool activate +eventIn SFBool reverseActivate FALSE +exposedField SFCommandBuffer buffer "" +eventOut SFBool isActive +]{ +} + +PROTO Cone [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +field SFFloat bottomRadius 1 #%b=[0,+I) #%q=11 +field SFFloat height 2 #%b=[0,+I) #%q=11 +field SFBool side TRUE +field SFBool bottom TRUE +] { +} + +PROTO Coordinate [ #%NDT=SFWorldNode,SFCoordinateNode %COD=N +exposedField MFVec3f point [] #%b=(-I,+I) #%q=1 #%a=1 +] { +} + +PROTO Coordinate2D [ #%NDT=SFWorldNode,SFCoordinate2DNode %COD=N +exposedField MFVec2f point [] #%b=(-I,+I) #%q=2 #%a=2 +] { +} + +PROTO CoordinateInterpolator [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFVec3f keyValue [] #%b=(-I,+I) #%q=1 +eventOut MFVec3f value_changed +] { +} + +PROTO CoordinateInterpolator2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFVec2f keyValue [] #%b=(-I,+I) #%q=2 +eventOut MFVec2f value_changed +] { +} + + +PROTO Curve2D [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFCoordinate2DNode point [] +exposedField SFFloat fineness 0.5 #%b=[0,1] #%q=0 #%a=7 +exposedField MFInt32 type [] #%b=[0,3] #%q=13 2 +] { +} + +PROTO Cylinder [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +field SFBool bottom TRUE +field SFFloat height 2 #%b=[0,+I) #%q=11 +field SFFloat radius 1 #%b=[0,+I) #%q=11 +field SFBool side TRUE +field SFBool top TRUE +] { +} + +PROTO CylinderSensor [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFBool autoOffset TRUE +exposedField SFFloat diskAngle 0.262 #%b=[0,1.5707963] #%q=6 +exposedField SFBool enabled TRUE +exposedField SFFloat maxAngle -1 #%b=[-6.2831853,6.2831853] #%q=6 +exposedField SFFloat minAngle 0 #%b=[-6.2831853,6.2831853] #%q=6 +exposedField SFFloat offset 0 #%b=[0,6.2831853] #%q=6 +eventOut SFBool isActive +eventOut SFRotation rotation_changed +eventOut SFVec3f trackPoint_changed +] { +} + +PROTO DirectionalLight [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFFloat ambientIntensity 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFColor color 1 1 1 #%b=[0,1] #%q=4 #%a=4 +exposedField SFVec3f direction 0 0 -1 #%q=9 #%a=9 +exposedField SFFloat intensity 1 #%b=[0,1] #%q=4 #%a=8 +exposedField SFBool on TRUE +] { +} + +PROTO DiscSensor [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFBool autoOffset TRUE +exposedField SFBool enabled TRUE +exposedField SFFloat maxAngle -1 #%b=[-6.2831853,6.2831853] #%q=6 +exposedField SFFloat minAngle 0 #%b=[-6.2831853,6.2831853] #%q=6 +exposedField SFFloat offset 0 #%b=[0,6.2831853] #%q=6 +eventOut SFBool isActive +eventOut SFFloat rotation_changed +eventOut SFVec2f trackPoint_changed +] { +} + +PROTO ElevationGrid [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFFloat set_height +exposedField SFColorNode color NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field MFFloat height [] #%b=(-I,+I) #%q=11 #%a=7 +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFFloat creaseAngle 0.0 #%b=[0,6.2831853] #%q=6 +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field SFInt32 xDimension 0 #%b=[0,+I) #%q=11 +field SFFloat xSpacing 1.0 #%b=(0,+I) #%q=11 +field SFInt32 zDimension 0 #%b=[0,+I) #%q=11 +field SFFloat zSpacing 1.0 #%b=[0,+I) #%q=11 +] { +} + + +PROTO Expression [ #%NDT=SFWorldNode,SFExpressionNode %COD=N +exposedField SFInt32 expression_select1 0 #%b=(0,31) #%q=13 5 +exposedField SFInt32 expression_intensity1 0 #%b=(0,63) #%q=13 6 +exposedField SFInt32 expression_select2 0 #%b=(0,31) #%q=13 5 +exposedField SFInt32 expression_intensity2 0 #%b=(0,63) #%q=13 6 +exposedField SFBool init_face FALSE +exposedField SFBool expression_def FALSE +] { +} + +PROTO Extrusion [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFVec2f set_crossSection +eventIn MFRotation set_orientation +eventIn MFVec2f set_scale +eventIn MFVec3f set_spine +field SFBool beginCap TRUE +field SFBool ccw TRUE +field SFBool convex TRUE +field SFFloat creaseAngle 0.0 #%b=[0,6.2831853] #%q=6 +field MFVec2f crossSection [ 1 1, 1 -1, -1 -1, -1 1, 1 1 ] #%b=(-I,+I) #%q=2 +field SFBool endCap TRUE +field MFRotation orientation [0 0 1 0] #%b=(-I,+I) #%q=10 +field MFVec2f scale [1 1] #%b=[0,+I) #%q=7 +field SFBool solid TRUE +field MFVec3f spine [ 0 0 0, 0 1 0 ] #%b=(-I,+I) #%q=1 +] { +} + +PROTO Face [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField SFFAPNode fap NULL +exposedField SFFDPNode fdp NULL +exposedField SFFITNode fit NULL +exposedField SFAudioNode ttsSource NULL +exposedField MF3DNode renderedFace [] +] { +} + + +PROTO FaceDefMesh [ #%NDT=SFWorldNode,SFFaceDefMeshNode %COD=N +field SF3DNode faceSceneGraphNode NULL +field MFInt32 intervalBorders [] #%q=0 +field MFInt32 coordIndex [] #%q=0 +field MFVec3f displacements [] #%q=0 +] { +} + +PROTO FaceDefTables [ #%NDT=SFWorldNode,SFFaceDefTablesNode %COD=N +field SFInt32 fapID 1 #%b=[1, 68] #%q=13 7 +field SFInt32 highLevelSelect 1 #%b=[1, 64] #%q=13 6 +exposedField MFFaceDefMeshNode faceDefMesh [] +exposedField MFFaceDefTransformNode faceDefTransform [] +] { +} + +PROTO FaceDefTransform [ #%NDT=SFWorldNode,SFFaceDefTransformNode %COD=N +field SF3DNode faceSceneGraphNode NULL +field SFInt32 fieldId 1 +field SFRotation rotationDef 0 0 1 0 #%b=(-I,+I) #%q=10 +field SFVec3f scaleDef 1 1 1 #%q=7 +field SFVec3f translationDef 0 0 0 #%q=1 +] { +} + +PROTO FAP [ #%NDT=SFWorldNode,SFFAPNode %COD=N +exposedField SFVisemeNode viseme NULL +exposedField SFExpressionNode expression NULL +exposedField SFInt32 open_jaw +I #%b=[0, +I) #%q=0 +exposedField SFInt32 lower_t_midlip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_b_midlip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 stretch_l_corner +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 stretch_r_corner +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lower_t_lip_lm +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lower_t_lip_rm +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lower_b_lip_lm +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lower_b_lip_rm +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_l_cornerlip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_r_cornerlip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 thrust_jaw +I #%b=[0,+I) #%q=0 +exposedField SFInt32 shift_jaw +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 push_b_lip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 push_t_lip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 depress_chin +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 close_t_l_eyelid +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 close_t_r_eyelid +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 close_b_l_eyelid +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 close_b_r_eyelid +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 yaw_l_eyeball +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 yaw_r_eyeball +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 pitch_l_eyeball +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 pitch_r_eyeball +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 thrust_l_eyeball +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 thrust_r_eyeball +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 dilate_l_pupil +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 dilate_r_pupil +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_l_i_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_r_i_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_l_m_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_r_m_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_l_o_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_r_o_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 squeeze_l_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 squeeze_r_eyebrow +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 puff_l_cheek +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 puff_r_cheek +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lift_l_cheek +I #%b=[0,+I) #%q=0 +exposedField SFInt32 lift_r_cheek +I #%b=[0,+I) #%q=0 +exposedField SFInt32 shift_tongue_tip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_tongue_tip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 thrust_tongue_tip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_tongue +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 tongue_roll +I #%b=[0,+I) #%q=0 +exposedField SFInt32 head_pitch +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 head_yaw +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 head_roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lower_t_midlip_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_b_midlip_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 stretch_l_cornerlip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 stretch_r_cornerlip +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lower_t_lip_lm_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 lower_t_lip_rm_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_b_lip_lm_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_b_lip_rm_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_l_cornerlip_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_r_cornerlip_o +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 stretch_l_nose +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 stretch_r_nose +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_nose +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 bend_nose +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_l_ear +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 raise_r_ear +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 pull_l_ear +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 pull_r_ear +I #%b=(-I,+I) #%q=0 +] { +} + +PROTO FDP [ #%NDT=SFWorldNode,SFFDPNode %COD=N +exposedField SFCoordinateNode featurePointsCoord NULL +exposedField SFTextureCoordinateNode textureCoord NULL +exposedField MFFaceDefTablesNode faceDefTables [] +exposedField MF3DNode faceSceneGraph [] +field SFBool useOrthoTexture FALSE +] { +} + + +PROTO FIT [ #%NDT=SFWorldNode,SFFITNode %COD=N +exposedField MFInt32 FAPs [] #%b=[-1,68] #%q=13 7 +exposedField MFInt32 Graph [] #%b=[0,68] #%q=13 7 +exposedField MFInt32 numeratorExp [] #%b=[0,15] #%q=13 4 +exposedField MFInt32 denominatorExp [] #%b=[0,15] #%q=13 4 +exposedField MFInt32 numeratorImpulse [] #%b=[0,1023] #%q=13 10 +exposedField MFInt32 numeratorTerms [] #%b=[0,10] #%q=13 4 +exposedField MFInt32 denominatorTerms [] #%b=[0,10] #%q=13 4 +exposedField MFFloat numeratorCoefs [] #%b=(-I,+I) +exposedField MFFloat denominatorCoefs [] #%b=(-I,+I) +] { +} + +PROTO Fog [ #%NDT=SFWorldNode,SF3DNode,SFFogNode %COD=N +exposedField SFColor color 1 1 1 #%b=[0,1] #%q=4 #%a=4 +exposedField SFString fogType "LINEAR" +exposedField SFFloat visibilityRange 0 #%b=[0,+I) #%q=11 #a=7 +eventIn SFBool set_bind +eventOut SFBool isBound +] { +} + + +PROTO FontStyle [ #%NDT=SFWorldNode,SFFontStyleNode %COD=N +exposedField MFString family ["SERIF"] +exposedField SFBool horizontal TRUE +exposedField MFString justify ["BEGIN"] +exposedField SFString language "" +exposedField SFBool leftToRight TRUE +exposedField SFFloat size 1.0 #%b=[0,+I) #%q=11 +exposedField SFFloat spacing 1.0 #%b=[0,+I) #%q=11 +exposedField SFString style "PLAIN" +exposedField SFBool topToBottom TRUE +] { +} + +PROTO Form [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFVec2f size -1 -1 #%b=[0,+I) #%q=12 #%a=12 +exposedField MFInt32 groups [] #%b=[-1,1022] #%q=13 10 +exposedField MFString constraints [] +exposedField MFInt32 groupsIndex [] #%b=[-1,1022] #%q=13 10 +]{} + + +PROTO Group [ #%NDT=SFWorldNode,SFTopNode,SF3DNode,SF2DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +] { +} + + +PROTO ImageTexture [ #%NDT=SFWorldNode,SFTextureNode %COD=N +exposedField MFURL url [] +field SFBool repeatS TRUE +field SFBool repeatT TRUE +] { +} + +PROTO IndexedFaceSet [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +eventIn MFInt32 set_normalIndex +eventIn MFInt32 set_texCoordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field MFInt32 colorIndex [] #%b=[-1,+I) #%q=14 +field SFBool colorPerVertex TRUE +field SFBool convex TRUE +field MFInt32 coordIndex [] #%b=[-1,+I) #%q=14 +field SFFloat creaseAngle 0.0 #%b=[0,6.2831853] #%q=6 +field MFInt32 normalIndex [] #%b=[-1,+I) #%q=14 +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field MFInt32 texCoordIndex [] #%b=[-1,+I) #%q=14 +] { +} + +PROTO IndexedFaceSet2D [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +eventIn MFInt32 set_texCoordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinate2DNode coord NULL +exposedField SFTextureCoordinateNode texCoord NULL +field MFInt32 colorIndex [] #%b=[-1,+I) #%q=14 +field SFBool colorPerVertex TRUE +field SFBool convex TRUE +field MFInt32 coordIndex [] #%b=[-1,+I) #%q=14 +field MFInt32 texCoordIndex [] #%b=[-1,+I) #%q=14 +] { +} + +PROTO IndexedLineSet [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +field MFInt32 colorIndex [] #%b=[-1,+I) #%q=14 +field SFBool colorPerVertex TRUE +field MFInt32 coordIndex [] #%b=[-1,+I) #%q=14 +] { +} + +PROTO IndexedLineSet2D [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinate2DNode coord NULL +field MFInt32 colorIndex [] #%b=[-1,+I) #%q=14 +field SFBool colorPerVertex TRUE +field MFInt32 coordIndex [] #%b=[-1,+I) #%q=14 +]{ +} + +PROTO Inline [ #%NDT=SFWorldNode,SF3DNode,SFStreamingNode,SF2DNode %COD=N +exposedField MFURL url [] +] { +} + + +PROTO LOD [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField MF3DNode level [] +field SFVec3f center 0 0 0 #%b=(-I,+I) #%q=1 +field MFFloat range [] #%b=[0,+I] #%q=11 +] { +} + +PROTO Layer2D [ #%NDT=SFWorldNode,SFTopNode,SF2DNode,SF3DNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFVec2f size -1 -1 #%b=(-I,+I) #%q=12 #%a=12 +exposedField SFBackground2DNode background NULL +exposedField SFViewportNode viewport NULL +] { +} + +PROTO Layer3D [ #%NDT=SFWorldNode,SFTopNode,SF2DNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFVec2f size -1 -1 #%b=(-I,+I) #%q=12 #%a=12 +exposedField SFBackground3DNode background NULL +exposedField SFFogNode fog NULL +exposedField SFNavigationInfoNode navigationInfo NULL +exposedField SFViewpointNode viewpoint NULL +] { +} + + +PROTO Layout [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFBool wrap FALSE +exposedField SFVec2f size -1 -1 #%b=[0,+I) #%q=12 #%a=12 +exposedField SFBool horizontal TRUE +exposedField MFString justify ["BEGIN"] +exposedField SFBool leftToRight TRUE +exposedField SFBool topToBottom TRUE +exposedField SFFloat spacing 1 #%b=[0,+I) #%q=0 #%a=7 +exposedField SFBool smoothScroll FALSE +exposedField SFBool loop FALSE +exposedField SFBool scrollVertical TRUE +exposedField SFFloat scrollRate 0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFInt32 scrollMode 0 #%b=[-1,1] #%q=13 2 +]{} + +PROTO LineProperties [ #%NDT=SFWorldNode,SFLinePropertiesNode %COD=N +exposedField SFColor lineColor 0 0 0 #%b=[0,1] #%q=4 #%a=4 +exposedField SFInt32 lineStyle 0 #%b=[0,5] #%q=13 3 +exposedField SFFloat width 1 #%b=[0,+I) #%q=12 #%a=7 +]{ +} + +PROTO ListeningPoint [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFBool set_bind +exposedField SFBool jump TRUE +exposedField SFRotation orientation 0 0 1 0 #%q=10 #%a=10 +exposedField SFVec3f position 0 0 10 #%b=(-I,+I) #%q=1 #%a=1 +field SFString description "" +eventOut SFTime bindTime +eventOut SFBool isBound +] { +} + +PROTO Material [ #%NDT=SFWorldNode,SFMaterialNode %COD=N +exposedField SFFloat ambientIntensity 0.2 #%b=[0,1] #%q=4 #%a=8 +exposedField SFColor diffuseColor 0.8 0.8 0.8 #%b=[0,1] #%q=4 #%a=4 +exposedField SFColor emissiveColor 0 0 0 #%b=[0,1] #%q=4 #%a=4 +exposedField SFFloat shininess 0.2 #%b=[0,1] #%q=4 #%a=8 +exposedField SFColor specularColor 0 0 0 #%b=[0,1] #%q=4 #%a=4 +exposedField SFFloat transparency 0 #%b=[0,1] #%q=4 #%a=8 +] { +} + +PROTO Material2D [ #%NDT=SFWorldNode,SFMaterialNode %COD=N +exposedField SFColor emissiveColor 0.8 0.8 0.8 #%b=[0,1] #%q=4 #%a=4 +exposedField SFBool filled FALSE +exposedField SFLinePropertiesNode lineProps NULL +exposedField SFFloat transparency 0 #%b=[0,1] #%q=4 #%a=8 +]{ +} + +PROTO MovieTexture [ #%NDT=SFWorldNode,SFTextureNode,SFStreamingNode %COD=N +exposedField SFBool loop FALSE +exposedField SFFloat speed 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFTime startTime 0 #%b=(-I,+I) +exposedField SFTime stopTime 0 #%b=(-I,+I) +exposedField MFURL url [] +field SFBool repeatS TRUE +field SFBool repeatT TRUE +eventOut SFTime duration_changed +eventOut SFBool isActive +] { +} + +PROTO NavigationInfo [ #%NDT=SFWorldNode,SF3DNode,SFNavigationInfoNode %COD=N +eventIn SFBool set_bind +exposedField MFFloat avatarSize [0.25, 1.6, 0.75] # %b=[0,+I) #%q=11 +exposedField SFBool headlight TRUE +exposedField SFFloat speed 1.0 # %b=[0,+I) #%q=0 +exposedField MFString type ["WALK", "ANY"] +exposedField SFFloat visibilityLimit 0.0 # %b=[0,+I) #%q=11 #%a=7 +eventOut SFBool isBound +]{ +} + +PROTO Normal [ #%NDT=SFWorldNode,SFNormalNode %COD=N +exposedField MFVec3f vector [] #%q=9 #%a=9 +] { +} + +PROTO NormalInterpolator [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFVec3f keyValue [] #%b=(-I,+I) #%q=9 +eventOut MFVec3f value_changed +] { +} + +PROTO OrderedGroup [ #%NDT=SFWorldNode,SF3DNode,SF2DNode,SFTopNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField MFFloat order [] #%b=[0,+I) #%q=3 +] { +} + +PROTO OrientationInterpolator [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFRotation keyValue [] #%b=(-I,+I) #%q=10 +eventOut SFRotation value_changed +] { +} + + +PROTO PixelTexture [ #%NDT=SFWorldNode,SFTextureNode %COD=N +exposedField SFImage image 0 0 0 # %q=0 +field SFBool repeatS TRUE +field SFBool repeatT TRUE +] { +} + +PROTO PlaneSensor [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFBool autoOffset TRUE +exposedField SFBool enabled TRUE +exposedField SFVec2f maxPosition -1 -1 #%b=(-I,+I) #%q=2 +exposedField SFVec2f minPosition 0 0 #%b=(-I,+I) #%q=2 +exposedField SFVec3f offset 0 0 0 #%b=(-I,+I) #%q=1 +eventOut SFBool isActive +eventOut SFVec3f trackPoint_changed +eventOut SFVec3f translation_changed +] { +} + +PROTO PlaneSensor2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFBool autoOffset TRUE +exposedField SFBool enabled TRUE +exposedField SFVec2f maxPosition 0 0 #%b=(-I,+I) #%q=2 +exposedField SFVec2f minPosition 0 0 #%b=(-I,+I) #%q=2 +exposedField SFVec2f offset 0 0 #%b=(-I,+I) #%q=12 +eventOut SFBool isActive +eventOut SFVec2f trackPoint_changed +eventOut SFVec2f translation_changed +] { +} + +PROTO PointLight [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFFloat ambientIntensity 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFVec3f attenuation 1 0 0 #%b=[0,+I) #%q=11 #%a=1 +exposedField SFColor color 1 1 1 #%b=[0,1] #%q=4 #%a=4 +exposedField SFFloat intensity 1 #%b=[0,1] #%q=4 #%a=8 +exposedField SFVec3f location 0 0 0 #%b=(-I,+I) #%q=1 #%a=1 +exposedField SFBool on TRUE +exposedField SFFloat radius 100 #%b=[0,+I) #%q=11 #%a=7 +] { +} + +PROTO PointSet [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +] { +} + +PROTO PointSet2D [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFColorNode color NULL +exposedField SFCoordinate2DNode coord NULL +]{ +} + + +PROTO PositionInterpolator [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFVec3f keyValue [] #%b=(-I,+I) #%q=1 +eventOut SFVec3f value_changed +] { +} + +PROTO PositionInterpolator2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFVec2f keyValue [] #%b=(-I,+I) #%q=2 +eventOut SFVec2f value_changed +] { +} + +PROTO ProximitySensor2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFVec2f center 0 0 #%b=[-1,+I) #%q=2 +exposedField SFVec2f size 0 0 #%b=[0,+I) #%q=12 +exposedField SFBool enabled TRUE +eventOut SFBool isActive +eventOut SFVec2f position_changed +eventOut SFFloat orientation_changed +eventOut SFTime enterTime +eventOut SFTime exitTime +] { +} + +PROTO ProximitySensor [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFVec3f center 0 0 0 #%b=(-I,+I) #%q=1 +exposedField SFVec3f size 0 0 0 #%b=[0,+I) #%q=11 +exposedField SFBool enabled TRUE +eventOut SFBool isActive +eventOut SFVec3f position_changed +eventOut SFRotation orientation_changed +eventOut SFTime enterTime +eventOut SFTime exitTime +] { +} + +PROTO QuantizationParameter [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +field SFBool isLocal FALSE +field SFBool position3DQuant FALSE +field SFVec3f position3DMin -I -I -I #%b=(-I,+I) #%q=0 +field SFVec3f position3DMax +I +I +I #%b=(-I,+I) #%q=0 +field SFInt32 position3DNbBits 16 #%b=[0,31] #%q=13 5 +field SFBool position2DQuant FALSE +field SFVec2f position2DMin -I -I #%b=(-I,+I) #%q=0 +field SFVec2f position2DMax +I +I #%b=(-I,+I) #%q=0 +field SFInt32 position2DNbBits 16 #%b=[0,31] #%q=13 5 +field SFBool drawOrderQuant FALSE +field SFFloat drawOrderMin -I #%b=(-I,+I) #%q=0 +field SFFloat drawOrderMax +I #%b=(-I,+I) #%q=0 +field SFInt32 drawOrderNbBits 8 #%b=[0,31] #%q=13 5 +field SFBool colorQuant TRUE +field SFFloat colorMin 0.0 #%b=[0,1] #%q=0 +field SFFloat colorMax 1.0 #%b=[0,1] #%q=0 +field SFInt32 colorNbBits 8 #%b=[0,31] #%q=13 5 +field SFBool textureCoordinateQuant TRUE +field SFFloat textureCoordinateMin 0 #%b=[0,1] #%q=0 +field SFFloat textureCoordinateMax 1 #%b=[0,1] #%q=0 +field SFInt32 textureCoordinateNbBits 16 #%b=[0,31] #%q=13 5 +field SFBool angleQuant TRUE +field SFFloat angleMin 0.0 #%b=[0,6.2831853] #%q=0 +field SFFloat angleMax 6.2831853 #%b=[0,6.2831853] #%q=0 +field SFInt32 angleNbBits 16 #%b=[0,31] #%q=13 5 +field SFBool scaleQuant FALSE +field SFFloat scaleMin 0.0 #%b=(-I,+I) #%q=0 +field SFFloat scaleMax +I #%b=(-I,+I) #%q=0 +field SFInt32 scaleNbBits 8 #%b=[0,31] #%q=13 5 +field SFBool keyQuant TRUE +field SFFloat keyMin 0.0 #%b=(-I,+I) #%q=0 +field SFFloat keyMax 1.0 #%b=(-I,+I) #%q=0 +field SFInt32 keyNbBits 8 #%b=[0,31] #%q=13 5 +field SFBool normalQuant TRUE +field SFInt32 normalNbBits 8 #%b=[0,31] #%q=13 5 +field SFBool sizeQuant FALSE +field SFFloat sizeMin 0 #%b=(-I,+I) #%q=0 +field SFFloat sizeMax +I #%b=(-I,+I) #%q=0 +field SFInt32 sizeNbBits 8 #%b=[0,31] #%q=13 5 +field SFBool useEfficientCoding FALSE +]{ +} + +PROTO Rectangle [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFVec2f size 2 2 #%b=[0,+I) #%q=12 #%a=2 +]{ +} + +PROTO ScalarInterpolator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFFloat keyValue [] #%b=(-I,+I) #%q=0 +eventOut SFFloat value_changed +]{} + +PROTO Script [#%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=S +exposedField MFScript url [] +field SFBool directOutput FALSE +field SFBool mustEvaluate FALSE +]{ +} + +PROTO Shape [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField SFAppearanceNode appearance NULL +exposedField SFGeometryNode geometry NULL +] { +} + +PROTO Sound [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFVec3f direction 0 0 1 #%b=(-I,+I) #%q=9 +exposedField SFFloat intensity 1 #%b=[0,1] #%q=4 #%a=7 +exposedField SFVec3f location 0 0 0 #%b=(-I,+I) #%q=1 #%a=1 +exposedField SFFloat maxBack 10 #%b=[0,+I) #%q=11 #%a=7 +exposedField SFFloat maxFront 10 #%b=[0,+I) #%q=11 #%a=7 +exposedField SFFloat minBack 1 #%b=[0,+I) #%q=11 #%a=7 +exposedField SFFloat minFront 1 #%b=[0,+I) #%q=11 #%a=7 +exposedField SFFloat priority 0 #%b=[0,1] #%q=4 +exposedField SFAudioNode source NULL +field SFBool spatialize TRUE +] { +} + +PROTO Sound2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFFloat intensity 1 #%b=[0,1] #%q=4 #%a=7 +exposedField SFVec2f location 0 0 #%b=(-I,+I) #%q=2 #%a=2 +exposedField SFAudioNode source NULL +field SFBool spatialize TRUE +]{ +} + +PROTO Sphere [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +field SFFloat radius 1 #%b=(0,+I) #%q=11 +] { +} + + +PROTO SphereSensor [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFBool autoOffset TRUE +exposedField SFBool enabled TRUE +exposedField SFRotation offset 0 1 0 0 # %b=(-I,+I) #%q=10 +eventOut SFBool isActive +eventOut SFRotation rotation_changed +eventOut SFVec3f trackPoint_changed +]{ +} + +PROTO SpotLight [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFFloat ambientIntensity 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFVec3f attenuation 1 0 0 #%b=[0,+I) #%q=11 #%a=1 +exposedField SFFloat beamWidth 1.570796 #%b=[0,1.5707963] #%q=6 #%a=8 +exposedField SFColor color 1 1 1 #%b=[0,1] #%q=4 #%a=4 +exposedField SFFloat cutOffAngle 0.785398 #%b=[0,1.5707963] #%q=6 #%a=8 +exposedField SFVec3f direction 0 0 -1 #%b=(-I,+I) #%q=9 #%a=9 +exposedField SFFloat intensity 1 #%b=[0,1] #%q=4 #%a=8 +exposedField SFVec3f location 0 0 0 #%b=(-I,+I) #%q=1 #%a=1 +exposedField SFBool on TRUE +exposedField SFFloat radius 100 #%b=[0,+I) #%q=11 #%a=7 +] { +} + +PROTO Switch [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField MF3DNode choice [] +exposedField SFInt32 whichChoice -1 #%b=[-1, 1022] #%q=13 10 +] { +} + +PROTO TermCap [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFTime evaluate +exposedField SFInt32 capability 0 #%b=[0,127] #%q=13 7 +eventOut SFInt32 value 0 #%b=[0,7] #%q=13 3 +] { +} + +PROTO Text [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField MFString string [] +exposedField MFFloat length [] #%b=[0,+I) #%q=11 #%a=7 +exposedField SFFontStyleNode fontStyle NULL +exposedField SFFloat maxExtent 0.0 #%b=[0,+I) #%q=11 #%a=7 +] { +} + +PROTO TextureCoordinate [ #%NDT=SFWorldNode,SFTextureCoordinateNode %COD=N +exposedField MFVec2f point [] #%b=(-I,+I) #%q=5 #%a=2 +]{ +} + +PROTO TextureTransform [ #%NDT=SFWorldNode,SFTextureTransformNode %COD=N +exposedField SFVec2f center 0 0 #%b=(-I,+I) #%q=2 #%a=2 +exposedField SFFloat rotation 0 #%b=[0,6.2831853] #%q=6 #%a=6 +exposedField SFVec2f scale 1 1 #%b=(-I,+I) #%q=7 #%a=12 +exposedField SFVec2f translation 0 0 #%b=(-I,+I) #%q=2 #%a=2 +] { +} + +PROTO TimeSensor [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField SFTime cycleInterval 1 #%b=(0,+I) +exposedField SFBool enabled TRUE +exposedField SFBool loop FALSE +exposedField SFTime startTime 0 #%b=(-I,+I) +exposedField SFTime stopTime 0 #%b=(-I,+I) +eventOut SFTime cycleTime +eventOut SFFloat fraction_changed +eventOut SFBool isActive +eventOut SFTime time +] { +} + +PROTO TouchSensor [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFBool enabled TRUE +eventOut SFVec3f hitNormal_changed +eventOut SFVec3f hitPoint_changed +eventOut SFVec2f hitTexCoord_changed +eventOut SFBool isActive +eventOut SFBool isOver +eventOut SFTime touchTime +] {} + +PROTO Transform [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField SFVec3f center 0 0 0 #%b=(-I,+I) #%q=1 #%a=1 +exposedField MF3DNode children [] +exposedField SFRotation rotation 0 0 1 0 #%q=10 #%a=10 +exposedField SFVec3f scale 1 1 1 #%b=(0,+I) #%q=7 #%a=11 +exposedField SFRotation scaleOrientation 0 0 1 0 #%q=10 #%a=10 +exposedField SFVec3f translation 0 0 0 #%b=(-I,+I) #%q=1 #%a=1 +] { +} + +PROTO Transform2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFVec2f center 0 0 #%b=(-I,+I) #%q=2 #%a=2 +exposedField SFFloat rotationAngle 0 #%b=[0,6.2831853] #%q=6 #%a=6 +exposedField SFVec2f scale 1 1 #%b=(-I,+I) #%q=7 #%a=12 +exposedField SFFloat scaleOrientation 0 #%b=[0,6.2831853] #%q=6 #%a=6 +exposedField SFVec2f translation 0 0 #%b=(-I,+I) #%q=2 #%a=2 +] { +} + +PROTO Valuator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +eventIn SFBool inSFBool +eventIn SFColor inSFColor +eventIn MFColor inMFColor +eventIn SFFloat inSFFloat +eventIn MFFloat inMFFloat +eventIn SFInt32 inSFInt32 +eventIn MFInt32 inMFInt32 +eventIn SFRotation inSFRotation +eventIn MFRotation inMFRotation +eventIn SFString inSFString +eventIn MFString inMFString +eventIn SFTime inSFTime +eventIn SFVec2f inSFVec2f +eventIn MFVec2f inMFVec2f +eventIn SFVec3f inSFVec3f +eventIn MFVec3f inMFVec3f +eventOut SFBool outSFBool +eventOut SFColor outSFColor +eventOut MFColor outMFColor +eventOut SFFloat outSFFloat +eventOut MFFloat outMFFloat +eventOut SFInt32 outSFInt32 +eventOut MFInt32 outMFInt32 +eventOut SFRotation outSFRotation +eventOut MFRotation outMFRotation +eventOut SFString outSFString +eventOut MFString outMFString +eventOut SFTime outSFTime +eventOut SFVec2f outSFVec2f +eventOut MFVec2f outMFVec2f +eventOut SFVec3f outSFVec3f +eventOut MFVec3f outMFVec3f +exposedField SFFloat Factor1 1.0 #%b=(-I,+I) #%q=0 +exposedField SFFloat Factor2 1.0 #%b=(-I,+I) #%q=0 +exposedField SFFloat Factor3 1.0 #%b=(-I,+I) #%q=0 +exposedField SFFloat Factor4 1.0 #%b=(-I,+I) #%q=0 +exposedField SFFloat Offset1 0.0 #%b=(-I,+I) #%q=0 +exposedField SFFloat Offset2 0.0 #%b=(-I,+I) #%q=0 +exposedField SFFloat Offset3 0.0 #%b=(-I,+I) #%q=0 +exposedField SFFloat Offset4 0.0 #%b=(-I,+I) #%q=0 +exposedField SFBool Sum FALSE +] { +} + +PROTO Viewpoint [ #%NDT=SFWorldNode,SF3DNode,SFViewpointNode %COD=N +eventIn SFBool set_bind +exposedField SFFloat fieldOfView 0.785398 #%b=[0,3.1415927] #%q=6 #%a=8 +exposedField SFBool jump TRUE +exposedField SFRotation orientation 0 0 1 0 #%q=10 #%a=10 +exposedField SFVec3f position 0 0 10 #%b=(-I,+I) #%q=1 #%a=1 +field SFString description "" +eventOut SFTime bindTime +eventOut SFBool isBound +] { +} + + +PROTO VisibilitySensor [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFVec3f center 0 0 0 # %b=(-I,+I) #%q=1 #%a=1 +exposedField SFBool enabled TRUE +exposedField SFVec3f size 0 0 0 # %b=[0,+I) #%q=11 #%a=11 +eventOut SFTime enterTime +eventOut SFTime exitTime +eventOut SFBool isActive +]{ +} + +PROTO Viseme [ #%NDT=SFWorldNode,SFVisemeNode %COD=N +exposedField SFInt32 viseme_select1 0 #%b=(0,31) #%q=13 5 +exposedField SFInt32 viseme_select2 0 #%b=(0,31) #%q=13 5 +exposedField SFInt32 viseme_blend 0 #%b=(0,63) #%q=13 6 +exposedField SFBool viseme_def FALSE +] { +} + +PROTO WorldInfo [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +field MFString info [] +field SFString title "" +] { +} diff --git a/applications/generators/MPEG4/templates10.txt b/applications/generators/MPEG4/templates10.txt new file mode 100644 index 0000000..1c4898a --- /dev/null +++ b/applications/generators/MPEG4/templates10.txt @@ -0,0 +1,53 @@ +PROTO CacheTexture [#%NDT=SFWorldNode,SF2DNode,SF3DNode,SFTextureNode %COD=N +field SFInt32 objectTypeIndication 0 +field SFString decoderSpecificInfo "" +field SFString image "" +field SFString cacheURL "" +field MFURL cacheOD [] +field SFInt32 expirationDate 0 +field SFBool repeatS TRUE +field SFBool repeatT TRUE +]{} + +PROTO EnvironmentTest [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFBool evaluate +exposedField SFBool enabled TRUE +exposedField SFInt32 parameter 0 +exposedField SFString compareValue "" +exposedField SFBool evaluateOnChange TRUE +eventOut SFBool valueLarger +eventOut SFBool valueEqual +eventOut SFBool valueSmaller +eventOut SFString parameterValue +] {} + + +PROTO KeyNavigator [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFBool setFocus +exposedField SF3DNode sensor NULL +exposedField SF2DNode left NULL +exposedField SF2DNode right NULL +exposedField SF2DNode up NULL +exposedField SF2DNode down NULL +exposedField SF2DNode select NULL +exposedField SF2DNode quit NULL +exposedField SFFloat step 0 +eventOut SFBool focusSet +]{} + +PROTO SpacePartition [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFURL SPStream NULL +]{} + +PROTO Storage [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFBool forceSave +eventIn SFBool forceRestore +exposedField SFBool auto TRUE +field SFInt32 expireAfter 0 +field SFString name "" +field MFAttrRef storageList [] +]{} + diff --git a/applications/generators/MPEG4/templates2.txt b/applications/generators/MPEG4/templates2.txt new file mode 100644 index 0000000..b3c013e --- /dev/null +++ b/applications/generators/MPEG4/templates2.txt @@ -0,0 +1,592 @@ +#-- Version 2 --# +# templates for the BIFS nodes of v2 +# ================================== +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 Reserved +# +# %a=y Animation method for fields that can be animated +# +## OO 081498 To match BIFS's update numbering +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying which node sub +# types the node belongs to. Moreover, each field of type SF/MF3DNode is re assigned +# a unique correct NodeDataType according to specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# JS: Created on 990726 +# _________________ +# YF: modified 990726 +# added NDT to nodes below, but probably incorrectly. +#BodySegmentConnectionHint [ #%NDT=SFWorldNode +#MaterialKey [#%NDT=SFWorldNode +#PROTO ServerCommand [#%NDT=SFWorldNode +#Hierarchical3DMesh {#%NDT=SFWorldNode +# +# JS: modified 990726 +# Cleaned up NDTs. +# re-ordered in the right order fields and events: eventIn, exposedField, field, eventOut +# => FPDAM needs to be changed accordingly +# corrected case of fields and event types! +# re-aligned stuff with spaces so that we may conserve a kind of alignment. Please be +# careful! did not finish for BAp, too long! +# +# YF: modified 990728 +# YF: fixed typo in Hierarchical3DMesh, finishd BAP allignment +# +# YF: modified 990729 +# YF: many more typos +# +# Aug 23, 1999 (Mikael Bourges-Sevenier) added body animation nodes from Tolga +# Aug 26, 1999 (Mikael Bourges-Sevenier) added body audio nodes from Riitta +# Sep 1, 1999 (MBS) cross-checked everything. +# Dec 20, 1999 YF +# bounds of form (x,y) changed to form [a,b] e.g.: +# numInterpolatorkeys gets new range [2,+I) +# bapIds gets new range [1,296] +# BAPs set to +I default value +# added application window +# +# 23.1.2000 (Riitta) +# Fixed AcousticMaterial, AcousticScene, DirectiveSound +# to comply with the latest spec (FDIS). +# +# Feb 8, 2000 (YF) NULL -> [] in BodySegmentConnectionHint +# remove "," from Vec3f values and put [ ] around MFFloat values +# +# July 27, 2000 (YF) NDT of Hierarchical3DMech changed to SFGeometryNode +# +# August 10, 2000 (YF per Steve Wood): +# Add [] around default values of MF field in AcousticMaterial, AcousticScene +# DirectiveSound, PerceptualParameters +# ApplicationWindow parameter field default value just [] + +#PROTO AcousticMaterial [#%NDT=SFMaterialNode,SFWorldNode %COD=N +#exposedField SFFloat ambientIntensity 0.2 #%b=[0,1] #%q=4 #%a=8 +#exposedField SFColor diffuseColor 0.8, 0.8, 0.8 #%b=[0,1] #%q=4 #%a=8 +#exposedField SFColor emissiveColor 0, 0, 0 #%b=[0,1] #%q=4 #%a=8 +#exposedField SFFloat shininess 0.2 #%b=[0,1] #%q=4 #%a=8 +#exposedField SFColor specularColor 0, 0, 0 #%b=[0,1] #%q=4 #%a=8 +#exposedField SFFloat transparency 0 #%b=[0,1] #%q=4 #%a=8 +#field SFFloat reffunc 0 #%b=(-I,+I) #%q=0 +#field SFFloat transfunc 1 #%b=(-I,+I) #%q=0 +#]{ +#} + +PROTO AcousticMaterial [#%NDT=SFMaterialNode,SFWorldNode %COD=N +exposedField SFFloat ambientIntensity 0.2 #%b=[0,1] #%q=4 #%a=8 +exposedField SFColor diffuseColor 0.8 0.8 0.8 #%b=[0,1] #%q=4 #%a=8 +exposedField SFColor emissiveColor 0 0 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFFloat shininess 0.2 #%b=[0,1] #%q=4 #%a=8 +exposedField SFColor specularColor 0 0 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFFloat transparency 0 #%b=[0,1] #%q=4 #%a=8 +field MFFloat reffunc [0] #%b=(-I,+I) #%q=0 +field MFFloat transfunc [1] #%b=(-I,+I) #%q=0 +field MFFloat refFrequency [0] #%b=(0,+I) #%q=0 +field MFFloat transFrequency [0] #%b=(0,+I) #%q=0 +]{ +} + +#PROTO AcousticScene [#%NDT=SFWorldNode,SF3DNode %COD=N +#exposedField SFFloat reverbLevel 0.4 #%b=(-I,+I) #%q=0 #%a=7 +#exposedField SFTime reverbDelay 0.5 #%b=(-I,+I) #%q=0 +#field SFVec3f center 0 0 0 #%b=(-I,+I) #%q=11 #%a=11 +#field SFVec3f Size -1 -1 -1 #%b=(-I,+I) #%q=1 #%a=1 +#field MFTime reverbTime [0] #%b=(-I,+I) #%q=0 +#field MFFloat reverbFreq [1000] #%b=(0 ,+I) #%q=0 +#]{ +#} + +PROTO AcousticScene [#%NDT=SFWorldNode,SF3DNode %COD=N +field SFVec3f center 0 0 0 #%b=(-I,+I) #%q=1 +field SFVec3f Size -1 -1 -1 #%b=(-I,+I) #%q=11 +field MFTime reverbTime [0] #%b=(0 ,+I) #%q=0 +field MFFloat reverbFreq [1000] #%b=(0 ,+I) #%q=0 +exposedField SFFloat reverbLevel 0.4 #%b=(0 ,+I) #%q=0 #%a=7 +exposedField SFTime reverbDelay 0.5 #%b=(0 ,+I) #%q=0 +]{ +} + +PROTO ApplicationWindow [#%NDT=SFWorldNode,SF2DNode %COD=N +exposedField SFBool isActive FALSE +exposedField SFTime startTime 0 #%b=(-I,+I) #%q=0 +exposedField SFTime stopTime 0 #%b=(-I,+I) #%q=0 +exposedField SFString description "" +exposedField MFString parameter [] +exposedField MFURL url [] +exposedField SFVec2f size 0 0 #%b=(-I,+I) #%q=12 #%a=12 +]{ +} + +PROTO BAP [#%NDT=SFWorldNode,SFBAPNode %COD=N +exposedField SFInt32 sacroiliac_tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 sacroiliac_torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 sacroiliac_roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_hip_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_hip_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_hip_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_hip_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_hip_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_hip_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_knee_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_knee_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_knee_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_knee_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ankle_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ankle_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ankle_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ankle_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_subtalar_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_subtalar_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_midtarsal_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_midtarsal_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_metatarsal_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_metatarsal_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_sternoclavicular_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_sternoclavicular_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_sternoclavicular_rotate +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_sternoclavicular_rotate +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_acromioclavicular_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_acromioclavicular_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_acromioclavicular_rotate +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_acromioclavicular_rotate +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_shoulder_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_shoulder_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_shoulder_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_shoulder_abduct +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_shoulder_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_shoulder_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_elbow_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_elbow_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_elbow_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_elbow_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_wrist_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_wrist_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_wrist_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_wrist_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_wrist_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_wrist_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 skullbase_roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 skullbase_torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 skullbase_tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc1roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc1torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc1tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc2roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc2torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc2tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc3roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc3torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc3tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc4roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc4torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc4tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc5roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc5torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc5tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc6roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc6torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc6tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc7roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc7torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vc7tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt1roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt1torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt1tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt2roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt2torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt2tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt3roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt3torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt3tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt4roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt4torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt4tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt5roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt5torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt5tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt6roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt6torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt6tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt7roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt7torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt7tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt8roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt8torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt8tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt9roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt9torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt9tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt10roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt10torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt10tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt11roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt11torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt11tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt12roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt12torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vt12tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl1roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl1torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl1tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl2roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl2torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl2tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl3roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl3torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl3tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl4roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl4torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl4tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl5roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl5torsion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 vl5tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_pinky0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_pinky0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_pinky1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_pinky1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_pinky1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_pinky1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_pinky1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_pinky1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_pinky2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_pinky2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_pinky3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_pinky3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ring0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ring0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ring1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ring1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ring1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ring1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ring1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ring1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ring2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ring2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_ring3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_ring3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_middle0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_middle0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_middle1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_middle1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_middle1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_middle1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_middle1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_middle1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_middle2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_middle2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_middle3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_middle3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_index0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_index0_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_index1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_index1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_index1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_index1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_index1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_index1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_index2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_index2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_index3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_index3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_thumb1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_thumb1_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_thumb1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_thumb1_pivot +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_thumb1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_thumb1_twisting +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_thumb2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_thumb2_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 l_thumb3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 r_thumb3_flexion +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 HumanoidRoot_tr_vertical +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 HumanoidRoot_tr_lateral +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 HumanoidRoot_tr_frontal +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 HumanoidRoot_rt_body_turn +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 HumanoidRoot_rt_body_roll +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 HumanoidRoot_rt_body_tilt +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap187 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap188 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap189 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap190 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap191 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap192 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap193 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap194 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap195 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap196 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap197 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap198 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap199 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap200 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap201 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap202 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap203 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap204 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap205 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap206 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap207 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap208 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap209 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap210 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap211 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap212 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap213 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap214 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap215 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap216 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap217 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap218 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap219 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap220 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap221 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap222 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap223 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap224 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap225 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap226 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap227 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap228 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap229 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap230 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap231 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap232 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap233 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap234 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap235 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap236 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap237 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap238 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap239 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap240 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap241 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap242 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap243 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap244 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap245 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap246 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap247 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap248 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap249 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap250 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap251 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap252 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap253 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap254 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap255 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap256 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap257 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap258 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap259 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap260 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap261 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap262 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap263 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap264 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap265 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap266 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap267 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap268 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap269 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap270 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap271 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap272 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap273 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap274 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap275 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap276 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap277 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap278 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap279 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap280 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap281 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap282 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap283 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap284 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap285 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap286 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap287 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap288 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap289 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap290 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap291 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap292 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap293 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap294 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap295 +I #%b=(-I,+I) #%q=0 +exposedField SFInt32 extensionBap296 +I #%b=(-I,+I) #%q=0 +] { +} + +PROTO BDP [#%NDT=SFWorldNode,SFBDPNode %COD=N +exposedField MFBodyDefTableNode bodyDefTables [] +exposedField MF3DNode bodySceneGraph [] +] { +} + +PROTO Body [#%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField SFBDPNode bdp NULL +exposedField SFBAPNode bap NULL +exposedField MF3DNode renderedBody [] +] +{ +} + +PROTO BodyDefTable [#%NDT=SFWorldNode,SFBodyDefTableNode %COD=N +exposedField SFString bodySceneGraphNodeName "" +exposedField MFInt32 bapIDs [] #%b=[1,296] #%q=13 9 +exposedField MFInt32 vertexIds [] #%b=[0,+I) #%q=0 +exposedField MFInt32 bapCombinations [] #%b=(-I,+I) #%q=0 +exposedField MFVec3f displacements [] +exposedField SFInt32 numInterpolateKeys 2 #%b=[2,+I) #%q=0 +] { +} + +PROTO BodySegmentConnectionHint [#%NDT=SFWorldNode,SFBodySegmentConnectionHintNode %COD=N +exposedField SFString firstSegmentNodeName "" +exposedField SFString secondSegmentNodeName "" +exposedField MFInt32 firstVertexIdList [] #%b=[0,+I) #%q=0 +exposedField MFInt32 secondVertexIdList [] #%b=[0,+I) #%q=0 +] { +} + +#PROTO DirectiveSound [#%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +#exposedField SFVec3f direction 0 0 -1 #%b=(-I,+I) #%q=9 #%a=9 +#exposedField SFFloat intensity 1 #%b=(-I,+I) #%q=0 #%a=7 +#exposedField SFVec3f location 0 0 0 #%b=(-I,+I) #%q=1 #%a=1 +#exposedField SFAudioNode source NULL +#exposedField SFPerceptualParameterNode perceptualParameters NULL +#exposedField SFBool roomEffect FALSE +#exposedField SFBool spatialize TRUE +#field MFFloat angles 1 #%b=[0,3.14159265] #%q=6 #%a=8 +#field MFFloat directivity 1 #%b=(-I,+I) #%q=0 +#field SFFloat speedOfSound 340 #%b=(-I,+I) #%q=1 #%a=1 +#field SFFloat distance 100 #%b=(-I,+I) #%q=0 +#field SFBool useAirabs FALSE +#]{ +#} + +PROTO DirectiveSound [#%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFVec3f direction 0 0 -1 #%b=(-I,+I) #%q=9 #%a=9 +exposedField SFFloat intensity 1 #%b=(0,+I) #%q=0 #%a=7 +exposedField SFVec3f location 0 0 0 #%b=(-I,+I) #%q=1 #%a=1 +exposedField SFAudioNode source NULL +exposedField SFPerceptualParameterNode perceptualParameters NULL +exposedField SFBool roomEffect FALSE +exposedField SFBool spatialize TRUE +field MFFloat directivity 1 #%b=(-I,+I) #%q=0 +field MFFloat angles 1 #%b=[0,3.14159265] #%q=6 +field MFFloat frequency [] #%b=(0,+I) #%q=0 +field SFFloat speedOfSound 340 #%b=(0,+I) #%q=1 +field SFFloat distance 100 #%b=(0,+I) #%q=0 +field SFBool useAirabs FALSE +]{ +} + +PROTO Hierarchical3DMesh [#%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn SFInt32 triangleBudget 1000 #%b=(-1,+I) #%q=0 +exposedField SFFloat level 1 #%b=(-1,+I) #%q=0 +field MFURL url [] +eventOut SFBool doneLoading +]{ +} + +PROTO MaterialKey [#%NDT=SFWorldNode,SFMaterialNode %COD=N +exposedField SFBool isKeyed TRUE +exposedField SFBool isRGB TRUE +exposedField SFColor keyColor 0 0 0 #%b=[0,1] #%q=4 #%a=4 +exposedField SFFloat lowThreshold 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFFloat highThreshold 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFFloat transparency 0 #%b=[0,1] #%q=4 #%a=8 +]{ +} + +PROTO PerceptualParameters [#%NDT=SFWorldNode,SFPerceptualParameterNode %COD=N +exposedField SFFloat sourcePresence 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat sourceWarmth 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat sourceBrilliance 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat roomPresence 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat runningReverberance 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat envelopment 0.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat lateReverberance 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat heavyness 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat liveness 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField MFFloat omniDirectivity [1.0] #%b=(-I,+I) #%q=0 #%a=7 +exposedField MFFloat directFilterGains [1.0, 1.0, 1.0] #%b=(-I,+I) #%q=0 #%a=7 +exposedField MFFloat inputFilterGains [1.0, 1.0, 1.0] #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat refDistance 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat freqLow 250.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFFloat freqHigh 4000.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFTime timeLimit1 0.02 #%b=(-I,+I) #%q=0 +exposedField SFTime timeLimit2 0.04 #%b=(-I,+I) #%q=0 +exposedField SFTime timeLimit3 0.1 #%b=(-I,+I) #%q=0 +exposedField SFTime modalDensity 0.8 #%b=(-I,+I) #%q=0 +]{ +} + +#PROTO ServerCommand [#%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +#eventIn SFBool trigger FALSE +#exposedField SFBool enable FALSE +#exposedField MFURL url [ ] +#eventIn SFString command "" +#]{ +#} + + + diff --git a/applications/generators/MPEG4/templates3.txt b/applications/generators/MPEG4/templates3.txt new file mode 100644 index 0000000..e2a0f4b --- /dev/null +++ b/applications/generators/MPEG4/templates3.txt @@ -0,0 +1,123 @@ +#-- Version 3 --# +# templates for the BIFS nodes of v3 +# ================================== +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 Reserved +# +# %a=y Animation method for fields that can be animated +# +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying +# which node sub types the node belongs to. Moreover, each field of type +# SF/MF3DNode is re assigned a unique correct NodeDataType according to +# specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# 10 Aug 2000 (YF per reflector discussion): +# TemporalGroup children is now an MFTemporalNode +# +# 12 Nov 2001 (YF per reflector discussion): +# reorder fields of ServerCommand to match specification +# +# 6 Jan 02 YF -- add default values for children field of TemporalTransform +# and TemporalGroup +# +# YF: Created on Jun 5, 2000 based on w3383 output from Geneva + +PROTO TemporalTransform [#%NDT=SFWorldNode,SF2DNode,SF3DNode,SFTemporalNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField MFURL url [] +exposedField SFTime startTime -1.0 +exposedField SFTime optimalDuration -1.0 +exposedField SFBool active FALSE +exposedField SFFloat speed 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFVec2f scalability 1.0 1.0 #%b=[-1,+I) #%q=12 #%a=12 +exposedField MFInt32 stretchMode [0] #%b=[0,2] #%q=13 2 +exposedField MFInt32 shrinkMode [0] #%b=[0,1] #%q=13 1 +exposedField SFTime maxDelay 0 +eventOut SFTime actualDuration +] { +} + + +PROTO TemporalGroup [#%NDT=SFWorldNode,SF2DNode,SF3DNode,SFTemporalNode %COD=N +eventIn MFTemporalNode addChildren +eventIn MFTemporalNode removeChildren +exposedField MFTemporalNode children [] +field SFBool costart TRUE +field SFBool coend FALSE +field SFBool meet FALSE +exposedField MFFloat priority [] #%b=[0,+I) #%q=3 +eventOut SFBool isActive +eventOut SFInt32 activeChild +]{ +} + +PROTO ServerCommand [#%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFBool trigger FALSE +exposedField SFBool enable FALSE +exposedField MFURL url [] +exposedField SFString command "" +]{ +} + + diff --git a/applications/generators/MPEG4/templates4.txt b/applications/generators/MPEG4/templates4.txt new file mode 100644 index 0000000..94458e8 --- /dev/null +++ b/applications/generators/MPEG4/templates4.txt @@ -0,0 +1,129 @@ +#-- Version 4 --# +# templates for the BIFS nodes +# ============================= +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 Reserved +# +# %a=y Animation method for fields that can be animated +# +## OO 081498 To match BIFS's update numbering +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying which node sub +# types the node belongs to. Moreover, each field of type SF/MF3DNode is re assigned +# a unique correct NodeDataType according to specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# Jan 29, 2000 created for v4 nodes (called group 4 now) +# +# Aug 21, 2001 Changed SFCommandBuffer from SFString buffer in InputSensor +# SFURL -> MFURL in MediaControl + +PROTO InputSensor [#%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFBool enabled TRUE +exposedField SFCommandBuffer buffer "" +exposedField MFURL url "" +eventOut SFTime eventTime +]{ +} + +PROTO MatteTexture [#%NDT=SFWorldNode,SFTextureNode,SF2DNode,SF3DNode %COD=N +field SFTextureNode surfaceA NULL +field SFTextureNode surfaceB NULL +field SFTextureNode alphaSurface NULL +exposedField SFString operation "" +field SFBool overwrite FALSE +exposedField SFFloat fraction 0 +exposedField MFFloat parameter 0 +]{ +} + +PROTO MediaBuffer [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFFloat bufferSize 0.0 #%b=[0,+I) +exposedField MFURL url [] +exposedField SFTime mediaStartTime -1 #%b=(-I,+I) +exposedField SFTime mediaStopTime +I #%b=(-I,+I) +eventOut SFBool isBuffered +exposedField SFBool enabled TRUE +] { +} + +PROTO MediaControl [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField MFURL url [] +exposedField SFTime mediaStartTime -1 #%b=(-I,+I) +exposedField SFTime mediaStopTime +I #%b=(-I,+I) +exposedField SFFloat mediaSpeed 1.0 #%b=(-I,+I) +exposedField SFBool loop FALSE +exposedField SFBool preRoll TRUE +exposedField SFBool mute FALSE +exposedField SFBool enabled TRUE +eventOut SFBool isPreRolled +] { +} + +PROTO MediaSensor [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField MFURL url [] +eventOut SFTime mediaCurrentTime +eventOut SFTime streamObjectStartTime +eventOut SFTime mediaDuration +eventOut SFBool isActive +eventOut MFString info +] { +} + diff --git a/applications/generators/MPEG4/templates5.txt b/applications/generators/MPEG4/templates5.txt new file mode 100644 index 0000000..21bbdd2 --- /dev/null +++ b/applications/generators/MPEG4/templates5.txt @@ -0,0 +1,561 @@ +#-- Version 5 --# +# templates for the BIFS nodes +# ============================= +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 SFVec4f +# 16 Reserved +# +# %a=y Animation method for fields that can be animated +# +## OO 081498 To match BIFS's update numbering +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying which node sub +# types the node belongs to. Moreover, each field of type SF/MF3DNode is re assigned +# a unique correct NodeDataType according to specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# March 18, 2004 [MBS] According to 68th meeting resolutions, removed Light-Field Mapping, Solid modeling and Particle systems related nodes. +# This includes the nodes: +# - +# Aug. 1, 2003 [MBS] According to 65th meeting resolutions, removed Multi-User Worlds nodes MUxxx +# Dec. 19, 2002 [MBS] According to 63rd meeting resolutions, removed Synthetic textures nodes: ColorProfile, SynthesizedTextureXXX, GradientLinear,GradientRadial,Ellipse +# Dec. 8, 2002 [MBS,MH] OctreeImage.image changed from MFTextureNode to MFDepthImageNode. DepthImage now also belongs to SFDepthImageNode context. +# Nov. 6, 2002 [MBS] modified nodes according to study of FPDAM (w5285). +# Oct 22, 2002 [MBS] added GradientRadial.Transform field which was missing but was in the spec. +# Aug 31, 2002 [MBS] +# changed SynthesizedTextureCurve.separatingFlags to MFInt32 since MFBool doesn't exist in VRML and bounds to 0 and 1 on 1 bit. +# For profileType, changed quantizer to 13 1 instead of 13 2 since values are 0 or 1 +# Aug 7, 2002 [MBS] aligned nodes to FDPAM +# May 9, 2002 [AFX] added quantizers, syntax check with PDAM +# January 28, 2002 [MBS] added rest of AFX nodes, alpha order everything +# January 6, 2002 [MBS] added AFX nodes +# December 7, 2001 [MBS, IG] created for AMD4 (v5) nodes + +# +# AFX nodes +# + +PROTO BitWrapper [ #%NDT=SFWorldNode,SF3DNode,SF2DNode,SFGeometryNode %COD=N +field SFWorldNode node NULL +field SFInt32 type 0 +field MFURL url [] +field SFString buffer "" +]{} + +PROTO CoordinateInterpolator4D [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFVec4f keyValue [] #%b=(-I,+I) #%q=15 +eventOut MFVec4f value_changed +] { +} + +PROTO DepthImage [ #%NDT=SFWorldNode,SF3DNode,SFDepthImageNode %COD=N +field SFDepthTextureNode diTexture NULL +field SFFloat farPlane 100 #%b=[0,+I] +field SFVec2f fieldOfView 0.785398 0.785398 #%b=[0,3.1415927] +field SFFloat nearPlane 10 #%b=[0,+I] +field SFRotation orientation 0 0 1 0 +field SFBool orthographic TRUE +field SFVec3f position 0 0 10 #%b=[-I,+I] +]{} + +PROTO FFD [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField MFVec4f controlPoint [] #%b=[-I,+I] #%q=15 #%a=15 +field SFInt32 uDimension 2 #%b=[2,257] #%q=13 8 +field MFFloat uKnot [] #%b=[-I,+I] +field SFInt32 uOrder 2 #%b=[2,33] #%q=13 5 +field SFInt32 vDimension 2 #%b=[2,257] #%q=13 8 +field MFFloat vKnot [] #%b=[-I,+I] +field SFInt32 vOrder 2 #%b=[2,33] #%q=13 5 +field SFInt32 wDimension 2 #%b=[2,257] #%q=13 8 +field MFFloat wKnot [] #%b=[-I,+I] +field SFInt32 wOrder 2 #%b=[2,33] #%q=13 5 +]{} + +PROTO Implicit [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFVec3f bboxSize 2 2 2 #%b=[0,+I] #%q=11 #%a=11 +exposedField MFFloat c [] #%b=[-I,+I] #%q=0 #%a=7 +exposedField MFInt32 densities [] #%b=[0,+I] +exposedField SFBool dual FALSE +exposedField SFBool solid FALSE +]{} + +# renamed as XX for deletion +PROTO XXLFM_Appearance [ #%NDT=SFWorldNode,SFAppearanceNode %COD=N +exposedField SFBlendListNode blendList NULL +exposedField MFLightMapNode lightMapList [] +exposedField MFTextureNode tileList [] +exposedField SFFrameListNode vertexFrameList NULL +]{} + +# renamed as XX for deletion +PROTO XXLFM_BlendList [ #%NDT=SFWorldNode,SFBlendListNode %COD=N +exposedField MFInt32 blendMode [] #%b=[0,1] #%q=13 1 +exposedField MFInt32 lightMapIndex [] #%q=14 +]{} + +# renamed as XX for deletion +PROTO XXLFM_FrameList [ #%NDT=SFWorldNode,SFFrameListNode %COD=N +exposedField MFInt32 index [ -1 ] #%q=14 +exposedField MFVec3f frame [ 1 0 0, 0 1 0, 0 0 1 ] #%b=[-1,1] #%q=1 +]{} + +# renamed as XX for deletion +PROTO XXLFM_LightMap [ #%NDT=SFWorldNode,SFLightMapNode %COD=N +exposedField SFVec3f biasRGB 0 0 0 #%b=[-1,1] #%q=7 +exposedField SFInt32 priorityLevel 0 #%b=[0,255] #%q=13 8 +exposedField SFVec3f scaleRGB 1 1 1 #%b=[-1,1] #%q=7 +exposedField SFSurfaceMapNode surfaceMapList NULL +exposedField SFViewMapNode viewMapList NULL +]{} + +# renamed as XX for deletion +PROTO XXLFM_SurfaceMapList [ #%NDT=SFWorldNode,SFSurfaceMapNode %COD=N +exposedField MFInt32 tileIndex [] #%q=14 +exposedField SFTextureCoordinateNode triangleCoordinate NULL +exposedField MFInt32 triangleIndex [] #%q=14 +exposedField MFInt32 viewMapIndex [] #%q=14 +]{} + +# renamed as XX for deletion +PROTO XXLFM_ViewMapList [ #%NDT=SFWorldNode,SFViewMapNode %COD=N +exposedField SFTextureCoordinateNode textureOrigin NULL +exposedField SFTextureCoordinateNode textureSize NULL +exposedField MFInt32 tileIndex [] #%q=14 +exposedField MFInt32 vertexIndex [] #%q=14 +]{} + +PROTO MeshGrid [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +eventIn MFInt32 set_normalIndex +eventIn MFInt32 set_texCoordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFInt32 displayLevel 0 #%b=[0, +I] #%q=13 32 #%a=13 +exposedField SFInt32 filterType 0 #%b=[0, 1] #%q=13 2 #%a=13 +exposedField SFCoordinateNode gridCoord NULL +exposedField SFInt32 hierarchicalLevel 0 #%b=[-1, +I] #%q=13 32 #%a=13 +exposedField MFInt32 nLevels [] #%q=7 #%a=7 +exposedField SFNormalNode normal NULL +exposedField MFInt32 nSlices [] #%q=7 #%a=7 +exposedField SFTextureCoordinateNode texCoord NULL +exposedField MFFloat vertexOffset [] #%b=[0.0, 2.0] #%q=7 #%a=7 +exposedField MFInt32 vertexLink [] #%b=[0, 3] #%q=13 2 +field MFInt32 colorIndex [] #%b=[-1, +I] #%q=14 +field MFInt32 coordIndex [] #%b=[-1, +I] #%q=14 +field MFInt32 normalIndex [] #%b=[-1, +I] #%q=14 +field SFBool solid TRUE +field MFInt32 texCoordIndex [] #%b=[-1, +I] #%q=14 +eventOut SFBool isLoading +eventOut MFInt32 nVertices +]{} + +PROTO NonLinearDeformer [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFVec3f axis 0 0 1 #%b=[0,1] +exposedField MFFloat extend [] +exposedField SFGeometryNode geometry NULL +exposedField SFFloat param 0 +exposedField SFInt32 type 0 #%b=[0,2] +]{} + +PROTO NurbsCurve [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +exposedField SFColorNode color NULL +exposedField MFVec4f controlPoint [] #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFInt32 tessellation 0 #%b=[0,+I] +field MFInt32 colorIndex [] #%q=14 +field SFBool colorPerVertex TRUE +field MFFloat knot [] #%b=[-I,+I] +field SFInt32 order 4 #%b=[3,34] #%q=13 5 +]{} + +PROTO NurbsCurve2D [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +exposedField SFColorNode color NULL +exposedField MFVec3f controlPoint [] #%b=[-I,+I] #%q=2 #%a=2 +exposedField SFInt32 tessellation 0 #%b=[0,+I] +field MFInt32 colorIndex [] #%q=14 +field SFBool colorPerVertex TRUE +field MFFloat knot [] #%b=[-I,+I] +field SFInt32 order 4 #%b=[3,34] #%q=13 5 +]{} + +PROTO NurbsSurface [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_texColorIndex +exposedField SFColorNode color NULL +exposedField MFVec4f controlPoint [] #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFTextureCoordinateNode texCoord NULL +exposedField SFInt32 uTessellation 0 #%b=[0,+I] +exposedField SFInt32 vTessellation 0 #%b=[0,+I] +field SFBool ccw TRUE +field MFInt32 colorIndex [] #%q=14 +field SFBool colorPerVertex TRUE +field SFBool solid TRUE +field MFInt32 texColorIndex [] #%q=14 +field SFInt32 uDimension 4 #%b=[3,258] #%q=13 8 +field MFFloat uKnot [] #%b=[-I,+I] +field SFInt32 uOrder 4 #%b=[3,34] #%q=13 5 +field SFInt32 vDimension 4 #%b=[3,258] #%q=13 8 +field MFFloat vKnot [] #%b=[-I,+I] +field SFInt32 vOrder 4 #%b=[3,34] #%q=13 5 +]{} + +PROTO OctreeImage [ #%NDT=SFWorldNode,SF3DNode %COD=N +field MFDepthImageNode images [] +field MFInt32 octree [] #%b=[0,255] #%q=13 8 +field SFInt32 octreeResolution 256 #%b=[1,+I] +field MFInt32 voxelImageIndex [] #%b=[0,255] #%q=13 8 +]{} + +# renamed as XX for deletion +PROTO XXParticles [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFFloat creationRate 500 +exposedField SFFloat creationRateVariation 0 +exposedField SFFloat emitAlpha 1.0 +exposedField SFColor emitColor 1 1 1 +exposedField SFColor emitColorVariation 0 0 0 +exposedField SFVec3f emitterPosition 0 3 0 +exposedField SFVec3f emitVelocity 0 0 0 +exposedField SFVec3f emitVelocityVariation 1 1 1 +exposedField SFBool enabled TRUE +exposedField SFFloat fadeAlpha 1.0 +exposedField SFColor fadeColor 0.25 0.25 0.25 +exposedField SFFloat fadeRate 0.25 +exposedField SFVec3f force 0 -9.8 0 +exposedField MFInfluenceNode influences [] +exposedField SFWorldNode init NULL +exposedField SFTime maxLifeTime 5 +exposedField SFFloat maxLifeTimeVariation 0 +exposedField SFInt32 maxParticles 500 +exposedField SFFloat minRange 1 +exposedField SFFloat maxRange -1 +exposedField SFWorldNode primitive NULL +exposedField SFInt32 primitiveType 2 +exposedField SFFloat particleRadius 0.1 +exposedField SFFloat particleRadiusRate 0 +exposedField SFFloat particleRadiusVariation 0 +]{} + +# renamed as XX for deletion +PROTO XXParticleInitBox [ #%NDT=SFWorldNode,SFParticleInitializerNode %COD=N +exposedField SFFloat falloff 0 +exposedField SFVec3f size 1 1 1 +]{} + +# renamed as XX for deletion +PROTO XXPlanarObstacle [ #%NDT=SFWorldNode,SFInfluenceNode %COD=N +exposedField SFVec3f distance 0 0 0 +exposedField SFVec3f normal 0 1 0 +exposedField SFFloat reflection 0 +exposedField SFFloat absorption 0 +]{} + +# renamed as XX for deletion +PROTO XXPointAttractor [ #%NDT=SFWorldNode,SFInfluenceNode %COD=N +exposedField SFFloat innerRadius 10 +exposedField SFFloat outerRadius 100 +exposedField SFVec3f position 0 0 0 +exposedField SFFloat rate 1 +]{} + +PROTO PointTexture [ #%NDT=SFWorldNode,SFDepthTextureNode %COD=N +field MFColor color [] +field MFInt32 depth [] #%b=[0,+I] +field SFInt32 depthNbBits 7 #%b=[0,31] #%q=13 5 +field SFInt32 height 256 #%b=[1,+I] +field SFInt32 width 256 #%b=[1,+I] +]{} + +PROTO PositionAnimator [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField SFVec2f fromTo 0 1 #%q=8 +exposedField MFFloat key [] #%q=8 +exposedField MFRotation keyOrientation [] +exposedField SFInt32 keyType 0 +exposedField MFVec2f keySpline [0 0, 1 1 ] #%q=8 +exposedField MFVec3f keyValue [] #%q=4 +exposedField SFInt32 keyValueType 0 +exposedField SFVec3f offset 0 0 0 #%b=[-I,+I] #%q=1 +exposedField MFFloat weight [] #%b=[-1,1] +eventOut SFVec3f endValue +eventOut SFRotation rotation_changed +eventOut SFVec3f value_changed +]{} + +PROTO PositionAnimator2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField SFVec2f fromTo 0 1 #%q=8 +exposedField MFFloat key [] #%q=8 +exposedField SFInt32 keyOrientation 0 +exposedField SFInt32 keyType 0 +exposedField MFVec2f keySpline [0 0, 1 1 ] #%q=8 +exposedField MFVec2f keyValue [] #%q=4 +exposedField SFInt32 keyValueType 0 +exposedField SFVec2f offset 0 0 #%b=[-I,+I] #%q=2 +exposedField MFFloat weight [] #%b=[-1,1] +eventOut SFVec2f endValue +eventOut SFFloat rotation_changed +eventOut SFVec2f value_changed +]{} + +PROTO PositionInterpolator4D [ #%NDT=SFWorldNode,SF3DNode %COD=N +eventIn SFFloat set_fraction +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFVec4f keyValue [] #%b=(-I,+I) #%q=15 +eventOut SFVec4f value_changed +] { +} + +PROTO ProceduralTexture [ #%NDT=SFWorldNode,SFTextureNode %COD=N +exposedField SFBool aSmooth FALSE +exposedField MFVec2f aWarpmap [0 0, 1 1] #%b=[0,1] #%q=2 +exposedField MFFloat aWeights [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0] #%b=[-1,1] +exposedField SFBool bSmooth FALSE +exposedField MFVec2f bWarpmap [0 0, 1 1] #%b=[0, 1] #%q=2 +exposedField MFFloat bWeights [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0] #%b=[-1,1] +exposedField SFInt32 cellWidth 4 #%b=[0,15] #%q=13 4 +exposedField SFInt32 cellHeight 4 #%b=[0,15] #%q=13 4 +exposedField MFColor color [0.3 0.698 1, 0.8 0.8 0.8, 1 1 1, 0 0 0] #%q=4 +exposedField SFFloat distortion 0 #%b=[0,1] #%q=13 16 +exposedField SFInt32 height 7 #%b=[1,15] #%q=13 4 +exposedField SFInt32 roughness 0 #%b=[0,15] #%q=13 4 +exposedField SFInt32 seed 129093 #%b=[-I,+I] +exposedField SFInt32 type 0 #%b=[0,4] #%q=13 3 +exposedField SFBool xSmooth FALSE +exposedField MFVec2f xWarpmap [] #%b=[0,1] #%q=2 +exposedField SFBool ySmooth FALSE +exposedField MFVec2f yWarpmap [] #%b=[0,1] #%q=2 +exposedField SFInt32 width 7 #%b=[1,15] #%q=13 4 +eventOut SFImage image_changed +]{} + +PROTO Quadric [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFVec3f bboxSize 2 2 2 #%b=[0,+I] #%q=11 #%a=11 +exposedField MFInt32 densities [] #%b=[0,+I] +exposedField SFBool dual FALSE +exposedField SFVec4f P0 -1 0 0 1 #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFVec4f P1 1 0 0 1 #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFVec4f P2 0 1 0 0 #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFVec4f P3 0 0 1 0 #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFVec4f P4 0 1 0 1 #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFVec4f P5 0 0 1 1 #%b=[-I,+I] #%q=15 #%a=15 +exposedField SFBool solid FALSE +]{} + +PROTO SBBone [ #%NDT=SFWorldNode,SF2DNode,SF3DNode,SFSBBoneNode %COD=N +eventIn SF3DNode addChildren +eventIn SF3DNode removeChildren +exposedField SFInt32 boneID 0 #%b=[0,1023] #%q=13 10 +exposedField SFVec3f center 0 0 0 #%q=1 #%a=1 +exposedField MF3DNode children [] +exposedField SFVec3f endpoint 0 0 1 #%q=1 #%a=1 +exposedField SFInt32 falloff 1 #%b=[-1,4] #%q=13 3 +exposedField SFInt32 ikChainPosition 0 #%b=[0,3] #%q=13 2 +exposedField MFFloat ikPitchLimit [] +exposedField MFFloat ikRollLimit [] +exposedField MFFloat ikTxLimit [] +exposedField MFFloat ikTyLimit [] +exposedField MFFloat ikTzLimit [] +exposedField MFFloat ikYawLimit [] +exposedField SFRotation rotation 0 0 1 0 #%q=10 #%a=10 +exposedField SFInt32 rotationOrder 0 #%b=[0,23] #%q=13 5 +exposedField SFVec3f scale 0 0 0 #%q=7 #%a=11 +exposedField SFRotation scaleOrientation 0 0 1 0 #%q=10 #%a=10 +exposedField MFFloat sectionInner [] +exposedField MFFloat sectionOuter [] +exposedField MFFloat sectionPosition [] +exposedField MFInt32 skinCoordIndex [] #%q=14 +exposedField MFFloat skinCoordWeight [] #%b=[-1,1] +exposedField SFVec3f translation 0 0 0 #%q=1 #%a=1 +]{} + +PROTO SBMuscle [ #%NDT=SFWorldNode,SF2DNode,SF3DNode,SFSBMuscleNode %COD=N +exposedField SFInt32 falloff 1 #%b=[-1,4] #%q=13 3 +exposedField SFGeometryNode muscleCurve NULL +exposedField SFInt32 muscleID 0 #%b=[0,1023] #%q=13 10 +exposedField SFInt32 radius 1 #%q=7 #%a=11 +exposedField MFInt32 skinCoordIndex [] #%b=[0,+I] #%q=14 +exposedField MFFloat skinCoordWeight [] #%b=[-1,1] +]{} + +PROTO SBSegment [ #%NDT=SFWorldNode,SF2DNode,SF3DNode,SFSBSegmentNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField SFVec3f centerOfMass 0 0 0 #%q=1 #%a=1 +exposedField MF3DNode children [] +exposedField SFFloat mass 0 +exposedField MFVec3f momentsOfInertia [ 0 0 0, 0 0 0, 0 0 0 ] +exposedField SFString name "" +]{} + +PROTO SBSite [ #%NDT=SFWorldNode,SF2DNode,SF3DNode,SFSBSiteNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField SFVec3f center 0 0 0 #%q=1 #%a=1 +exposedField MF3DNode children [] +exposedField SFString name "" +exposedField SFRotation rotation 0 0 1 0 #%q=10 #%a=10 +exposedField SFVec3f scale 1 1 1 #%q=7 #%a=11 +exposedField SFRotation scaleOrientation 0 0 1 0 #%q=10 #%a=10 +exposedField SFVec3f translation 0 0 0 #%q=1 #%a=1 +]{} + +PROTO SBSkinnedModel [#%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField MFSBBoneNode bones [] +exposedField SFVec3f center 0 0 0 #%q=1 #%a=1 +exposedField MFSBMuscleNode muscles [] +exposedField SFString name "" +exposedField SFRotation rotation 0 0 1 0 #%q=10 #%a=10 +exposedField MFSBSegmentNode segments [] +exposedField SFVec3f scale 1 1 1 #%q=7 #%a=11 +exposedField SFRotation scaleOrientation 0 0 1 0 #%q=10 #%a=10 +exposedField MFSBSiteNode sites [] +exposedField MF3DNode skeleton [] +exposedField MF3DNode skin [] +exposedField SFCoordinateNode skinCoord NULL +exposedField SFNormalNode skinNormal NULL +exposedField SFVec3f translation 0 0 0 #%q=1 #%a=1 +exposedField SF3DNode weighsComputationSkinCoord NULL +]{} + +PROTO SBVCAnimation [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +exposedField MFURL url [] +exposedField MF3DNode virtualCharacters [] +]{} + +PROTO ScalarAnimator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N +eventIn SFFloat set_fraction +exposedField SFVec2f fromTo 0 1 #%q=8 +exposedField MFFloat key [] #%q=8 +exposedField SFInt32 keyType 0 +exposedField MFVec2f keySpline [0 0, 1 1 ] #%q=8 +exposedField MFFloat keyValue [] #%q=0 +exposedField SFInt32 keyValueType 0 +exposedField SFFloat offset 0 +exposedField MFFloat weight [] #%b=[-1,1] +eventOut SFFloat endValue +eventOut SFFloat value_changed +]{} + +PROTO SimpleTexture [ #%NDT=SFWorldNode,SFDepthTextureNode %COD=N +field SFTextureNode depth NULL +field SFTextureNode texture NULL +]{} + +PROTO SolidRep [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFVec3f bboxSize 2 2 2 #%b=[0,+I] #%q=11 #%a=11 +exposedField MFInt32 densityList [] #%b=[0,+I] +exposedField SF3DNode solidTree NULL +]{} + +PROTO SubdivisionSurface [ #%NDT=SFWorldNode,SFGeometryNode,SFBaseMeshNode %COD=N +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +eventIn MFInt32 set_cornerVertexIndex +eventIn MFInt32 set_creaseEdgeIndex +eventIn MFInt32 set_creaseVertexIndex +eventIn MFInt32 set_dartVertexIndex +eventIn MFInt32 set_texCoordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFTextureCoordinateNode texCoord NULL +exposedField MFSubdivSurfaceSectorNode sectors [] +exposedField SFInt32 subdivisionLevel 0 #%b=[-1,+I] +exposedField SFInt32 subdivisionType 0 #%b=[0,3] #%q=13 2 +exposedField SFInt32 subdivisionSubType 0 #%b=[0,3] #%q=13 2 +field MFInt32 invisibleEdgeIndex [] #%b=[0,+I] +field SFBool ccw TRUE +field MFInt32 colorIndex [] #%b=[-1,+I] +field SFBool colorPerVertex TRUE +field SFBool convex TRUE +field MFInt32 coordIndex [] #%b=[-1,+I] +field MFInt32 cornerVertexIndex [] #%b=[-1,+I] +field MFInt32 creaseEdgeIndex [] #%b=[-1,+I] +field MFInt32 creaseVertexIndex [] #%b=[-1,+I] +field MFInt32 dartVertexIndex [] #%b=[-1,+I] +field SFBool solid TRUE +field MFInt32 texCoordIndex [] #%b=[-1,+I] +]{} + +PROTO SubdivSurfaceSector [ #%NDT=SFWorldNode,SFSubdivSurfaceSectorNode %COD=N +exposedField SFFloat flatness 0 #%b=[0,1] #%q=7 +exposedField SFVec3f normal 0 0 0 #%q=9 +exposedField SFFloat normalTension 0 #%b=[0,1] #%q=7 +exposedField SFInt32 tag 0 #%b=[0,2] #%q=13 2 +exposedField SFFloat theta 0 #%b=[0,6.2831853] #%q=6 +field SFInt32 faceIndex 0 #%q=14 +field SFInt32 vertexIndex 0 #%q=14 +]{} + +PROTO WaveletSubdivisionSurface [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFGeometryNode baseMesh NULL +exposedField SFFloat fieldOfView 0.785398 # pi/4 +exposedField SFFloat frequency 1.0 +exposedField SFInt32 quality 1 +]{} + + + diff --git a/applications/generators/MPEG4/templates6.txt b/applications/generators/MPEG4/templates6.txt new file mode 100644 index 0000000..ab82832 --- /dev/null +++ b/applications/generators/MPEG4/templates6.txt @@ -0,0 +1,242 @@ +#-- Version 6 --# +#-- Beta Advanced Text Graphics --# +# templates for the BIFS nodes +# ============================= +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 Reserved +# +# %a=y Animation method for fields that can be animated +# +## OO 081498 To match BIFS's update numbering +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying which node sub +# types the node belongs to. Moreover, each field of type SF/MF3DNode is re assigned +# a unique correct NodeDataType according to specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# July 31, 2003 [CC, ENST] updated to FPDAM2 (w5774) +# April 28, 2003 [JLF, ENST] updated to PDAM (w5645) +# January 9, 2003 [JLF, ENST] updated to WD3.0 (w5475) +# September 17, 2002 [JLF, ENST] created for AdvancedText & Graphics WD 2.0 +#NB: XFontStyle.feature* MFInt32 fields should have some quantization type ? + +PROTO Clipper2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFGeometryNode geometry NULL +exposedField SFBool inside TRUE +exposedField SF2DNode transform NULL +exposedField SFBool XOR FALSE +] { +} + +PROTO ColorTransform [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFFloat mrr 1 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mrg 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mrb 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mra 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat tr 0 #%b=(-I, +I) #%q=4 #%a=7 +exposedField SFFloat mgr 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mgg 1 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mgb 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mga 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat tg 0 #%b=(-I, +I) #%q=4 #%a=7 +exposedField SFFloat mbr 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mbg 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mbb 1 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mba 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat tb 0 #%b=(-I, +I) #%q=4 #%a=7 +exposedField SFFloat mar 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mag 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mab 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat maa 1 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat ta 0 #%b=(-I, +I) #%q=4 #%a=7 +] { +} + +PROTO Ellipse [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFVec2f radius 1 1 #%b=[0,+I) #%q=12 #%a=2 +]{} + +PROTO LinearGradient [ #%NDT=SFWorldNode,SFTextureNode %COD=N +exposedField SFVec2f endPoint 1 0 #%b=(-I, +I) #%q=5 #%a=2 +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFColor keyValue [] #%b=[0,1] #%q=4 +exposedField MFFloat opacity [1] #%b=[0,1] #%q=7 +exposedField SFInt32 spreadMethod 0 #%b=[0,2] #%q=13 2 +exposedField SFVec2f startPoint 0 0 #%b=(-I, +I) #%q=5 #%a=2 +exposedField SF3DNode transform NULL +]{} + +PROTO PathLayout [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFGeometryNode geometry NULL +exposedField MFInt32 alignment [0 0] #%b=[-1,1] #%q=13 2 +exposedField SFFloat pathOffset 0 #%b=[-I,I] #%q=7 #%a=7 +exposedField SFFloat spacing 1.0 #%b=[-I,I] #%q=7 #%a=7 +exposedField SFBool reverseLayout FALSE +exposedField SFInt32 wrapMode 0 #%b=[0,2] #%q=13 2 +exposedField SFBool splitText TRUE +] { +} + +PROTO RadialGradient [ #%NDT=SFWorldNode,SFTextureNode %COD=N +exposedField SFVec2f center 0.5 0.5 #%b=(-I, +I) #%q=5 #%a=2 +exposedField SFVec2f focalPoint 0 0 #%b=(-I, +I) #%q=5 #%a=2 +exposedField MFFloat key [] #%b=[0,1] #%q=8 +exposedField MFColor keyValue [] #%b=[0,1] #%q=4 +exposedField MFFloat opacity [1] #%b=[0,1] #%q=7 +exposedField SFFloat radius 0.5 #%b=[0,+I) #%q=12 #%a=7 +exposedField SFInt32 spreadMethod 0 #%b=[0,2] #%q=13 2 +exposedField SF3DNode transform NULL +]{} + +PROTO SynthesizedTexture [ #%NDT=SFWorldNode,SFTextureNode %COD=N +exposedField MFVec3f translation [] #%b=[-I,+I] #%q=1 #%a=1 +exposedField MFRotation rotation [] #%b=[-I,+I] #%q=10 #%a=10 +exposedField SFInt32 pixelWidth -1 #%b=[0,65535] #%q=13 16 +exposedField SFInt32 pixelHeight -1 #%b=[0,65535] #%q=13 16 +exposedField SFBool loop FALSE +exposedField SFFloat speed 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFTime startTime 0 #%b=(-I,+I) +exposedField SFTime stopTime 0 #%b=(-I,+I) +exposedField MFURL url [] +eventOut SFTime duration_changed +eventOut SFBool isActive +]{ +} + +PROTO TransformMatrix2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode,SFTextureTransformNode %COD=N +eventIn MF2DNode addChildren +eventIn MF2DNode removeChildren +exposedField MF2DNode children [] +exposedField SFFloat mxx 1 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat mxy 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat tx 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat myx 0 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat myy 1 #%b=(-I, +I) #%q=7 #%a=7 +exposedField SFFloat ty 0 #%b=(-I, +I) #%q=7 #%a=7 +] { +} + +PROTO Viewport [ #%NDT=SFWorldNode,SF3DNode,SF2DNode,SFViewportNode %COD=N +eventIn SFBool set_bind +exposedField SFVec2f position 0 0 #%b=(-I,+I) #%q=1 #%a=1 +exposedField SFVec2f size -1 -1 #%b=(-I,+I) #%q=12 #%a=12 +exposedField SFFloat orientation 0 #%b=[0,6.2831853] #%q=6 #%a=6 +exposedField MFInt32 alignment [0 0] #%b=[-1,1] #%q=13 3 +exposedField SFInt32 fit 0 #%b=[0,2] #%q=13 3 +field SFString description "" +eventOut SFTime bindTime +eventOut SFBool isBound + +] { +} + +PROTO XCurve2D [ #%NDT=SFWorldNode,SFGeometryNode %COD=N +exposedField SFCoordinate2DNode point [] +exposedField SFFloat fineness 0.5 #%b=[0,1] #%q=0 #%a=7 +exposedField MFInt32 type [] #%b=[0,15] #%q=13 4 +] { +} + +PROTO XFontStyle [ #%NDT=SFWorldNode,SFFontStyleNode %COD=N +exposedField MFString fontName ["SERIF"] +exposedField SFBool horizontal TRUE +exposedField MFString justify ["BEGIN"] +exposedField SFString language "" +exposedField SFBool leftToRight TRUE +exposedField SFFloat size 1.0 #%b=[0,+I) #%q=11 +exposedField SFString stretch "NORMAL" +exposedField SFFloat letterSpacing 0.0 #%b=[0,+I) #%q=11 +exposedField SFFloat wordSpacing 0.0 #%b=[0,+I) #%q=11 +exposedField SFInt32 weight 400 +exposedField SFBool fontKerning TRUE +exposedField SFString style "PLAIN" +exposedField SFBool topToBottom TRUE +exposedField MFString featureName [""] +exposedField MFInt32 featureStartOffset [] #%b=(-I, +I) +exposedField MFInt32 featureLength [] #%b=(-I, +I) +exposedField MFInt32 featureValue [] #%b=(-I, +I) +] { +} + +PROTO XLineProperties [ #%NDT=SFWorldNode,SFLinePropertiesNode %COD=N +exposedField SFColor lineColor 0 0 0 #%b=[0,1] #%q=4 #%a=4 +exposedField SFInt32 lineStyle 0 #%b=[0,5] #%q=13 3 +exposedField SFBool isCenterAligned TRUE +exposedField SFBool isScalable TRUE +exposedField SFInt32 lineCap 0 #%b=[0,2] #%q=13 3 +exposedField SFInt32 lineJoin 0 #%b=[0,2] #%q=13 3 +exposedField SFFloat miterLimit 4 #%b=[1,+I) #%q=12 +exposedField SFFloat transparency 0 #%b=[0,1] #%q=4 #%a=8 +exposedField SFFloat width 1 #%b=[0,+I) #%q=12 #%a=7 +exposedField SFFloat dashOffset 0 #%b=[0,+I) #%q=12 #%a=7 +exposedField MFFloat dashes [] #%b=[0,+I) #%q=12 #%a=7 +exposedField SFTextureNode texture NULL +exposedField SFTextureTransformNode textureTransform NULL +]{ +} diff --git a/applications/generators/MPEG4/templates7.txt b/applications/generators/MPEG4/templates7.txt new file mode 100644 index 0000000..55b4536 --- /dev/null +++ b/applications/generators/MPEG4/templates7.txt @@ -0,0 +1,235 @@ +#-- Version 7 --# +# +# Beta for AFX/AMD1 +# +# templates for the BIFS nodes +# ============================= +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 SFVec4f +# 16 Reserved +# +# %a=y Animation method for fields that can be animated +# +## OO 081498 To match BIFS's update numbering +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying which node sub +# types the node belongs to. Moreover, each field of type SF/MF3DNode is re assigned +# a unique correct NodeDataType according to specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# March 18, 2003 [MBS] According to 68th meeting resolutions, created for AFX/AMD1 nodes + +# +# AFX/AMD1 nodes +# + + +PROTO AdvancedAudioBuffer [ #%NDT=SFWorldNode,SFAudioNode %COD=N +eventIn MFAudioNode addChildren +eventIn MFAudioNode removeChildren +exposedField MFAudioNode children [] +exposedField SFBool loop FALSE +exposedField SFFloat pitch 1.0 #%b=[0,+I] #%q=0 #%a=7 +exposedField SFTime startTime 0 #%b=[0,+I] #%q=0 +exposedField SFTime stopTime 0 #%b=[0,+I] #%q=0 +exposedField SFTime startLoadTime 0 #%b=[0,+I] #%q=0 +exposedField SFTime stopLoadTime 0 #%b=[0,+I] #%q=0 +exposedField SFInt32 loadMode 0 #%b=[0,4] #%q=13 3 +exposedField SFInt32 numAccumulatedBlocks 0 #%b=[0,65535] #%q=13 16 +exposedField SFInt32 deleteBlock 0 #%b=[-65536, 0] #%q=13 17 +exposedField SFInt32 playBlock 0 #%b=[-65536, 0] #%q=13 17 +exposedField SFFloat length 0.0 #%b=[0,+I] #%q=0 +field SFInt32 numChan 1 #%b=[0,255] #%q=13 8 +field MFInt32 phaseGroup [] #%b=[0,255] #%q=13 8 +eventOut SFTime duration_changed +eventOut SFBool isActive +]{} + + +PROTO AudioChannelConfig [ #%NDT=SFWorldNode,SFAudioNode %COD=N +eventIn MFAudioNode addChildren +eventIn MFAudioNode removeChildren +exposedField MFAudioNode children [] +exposedField SFInt32 generalChannelFormat 0 #%b=[0,4] #%q=13 3 +exposedField SFInt32 fixedPreset 0 #%b=[0,15] #%q=13 4 +exposedField SFInt32 fixedPresetSubset 0 +exposedField SFInt32 fixedPresetAddInf 0 #%b=[0,2] #%q=13 3 +exposedField MFInt32 channelCoordinateSystems [] #%b=[0,6] #%q=13 3 +exposedField MFFloat channelSoundLocation [] #%b=[-I,+I] +exposedField MFInt32 channelDirectionalPattern [] #%b=[0,2] #%q=13 3 +exposedField MFVec3f channelDirection [] +exposedField SFInt32 ambResolution2D 1 #%b=[0,127] #%q=13 7 +exposedField SFInt32 ambResolution3D 0 #%b=[0,15] #%q=13 4 +exposedField SFInt32 ambEncodingConvention 0 #%b=[0,5] #%q=13 3 +exposedField SFFloat ambNfcReferenceDistance 1.5 #%b=[0,+I] +exposedField SFFloat ambSoundSpeed 340.0 #%b=[0,+I] +exposedField SFInt32 ambArrangementRule 0 #%b=[0,7] #%q=13 3 +exposedField SFInt32 ambRecombinationPreset 0 #%b=[0,15] #%q=13 4 +exposedField MFInt32 ambComponentIndex [] #%b=[0,255] #%q=13 8 +exposedField MFFloat ambBackwardMatrix [] #%b=[-I,+I] +exposedField MFInt32 ambSoundfieldResolution [] #%b=[0,127] #%q=13 7 +field SFInt32 numChannel 0 #%b=[0,255] #%q=13 8 +]{} + +PROTO DepthImageV2 [ #%NDT=SFWorldNode,SF3DNode,SFDepthImageNode %COD=N +field SFDepthTextureNode diTexture NULL +field SFFloat farPlane 100 #%b=[0,+I] +field SFVec2f fieldOfView 0.75 0.75 #%b=[0,3.1415927] +field SFFloat nearPlane 10 #%b=[0,+I] +field SFRotation orientation 0 0 1 0 +field SFBool orthographic TRUE +field SFVec3f position 0 0 10 #%b=[-I,+I] +field SFVec2f splatMinMax 0.115 0.975 #%b=[-I,+I] +]{} + + +PROTO MorphShape [ #%NDT=SFWorldNode,SF3DNode,SF2DNode, %COD=N + exposedField SF3DNode baseShape NULL + exposedField SFInt32 morphID 0 #%b=[0, 1023] #%q=13 7 + exposedField MF3DNode targetShapes [ ] + exposedField MFFloat weights [ ] +]{} + +PROTO MultiTexture [ #%NDT=SFWorldNode,SFTextureNode %COD=N + exposedField SFFloat alpha 1 #%b=[0,1] + exposedField SFColor color 1 1 1 #%b=[0,1] + exposedField MFInt32 function [] + exposedField MFInt32 mode [] + exposedField MFInt32 source [] + exposedField MFTextureNode texture [] + exposedField MFVec3f cameraVector [] + exposedField SFBool transparent FALSE +]{} + +PROTO PointTextureV2 [ #%NDT=SFWorldNode,SFDepthTextureNode %COD=N +field MFColor color [] +field MFInt32 depth [] #%b=[0,+I] +field SFInt32 depthNbBits 7 #%b=[0,31] #%q=13 5 +field SFInt32 height 256 #%b=[1,+I] +field SFNormalNode normal NULL #%b=[-I,+I] +field MFVec3f splatU [] #%b=[-I,+I] #%q=1 +field MFVec3f splatV [] #%b=[-I,+I] #%q=1 +field SFInt32 width 256 #%b=[1,+I] +]{} + + +PROTO SBVCAnimationV2 [ #%NDT=SFWorldNode,SF3DNode,SF2DNode %COD=N + exposedField MFInt32 activeUrlIndex [] + exposedField SFBool loop FALSE + exposedField SFFloat speed 1.0 #%b=(-I,+I) #%q=0 #%a=7 + exposedField SFTime startTime 0 #%b=(-I,+I) + exposedField SFTime stopTime 0 #%b=(-I,+I) + exposedField SFFloat transitionTime 0 #%b=[0,+I) #%q=0 #%a=7 + exposedField MFURL url [ ] + exposedField MF3DNode virtualCharacters [ ] + eventOut SFTime duration_changed + eventOut SFBool isActive +]{} + +PROTO SimpleTextureV2 [ #%NDT=SFWorldNode,SFDepthTextureNode %COD=N +field SFTextureNode depth NULL +field SFTextureNode normal NULL +field SFTextureNode splatU NULL +field SFTextureNode splatV NULL +field SFTextureNode texture NULL +]{} + +PROTO SurroundingSound [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFAudioNode source NULL +exposedField SFFloat intensity 1.0 #%b=[0,1] #%q=0 #%a=7 +exposedField SFFloat distance 0.0 #%b=[0,+I] #%q=0 +exposedField SFVec3f location 0.0 0.0 0.0 #%b=[-I,+I] #%q=1 #%a=1 +exposedField SFFloat distortionFactor 0.0 #%b=[-I,+I] +exposedField SFRotation orientation 0.0 0.0 1.0 0.0 #%b=[-I,+I] #%q=10 #%a=10 +exposedField SFBool isTransformable TRUE +]{} + + +PROTO Transform3DAudio [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFFloat thirdCenterCoordinate 0.0 #%b=[-I,+I] #%q=0 #%a=7 +exposedField SFVec3f rotationVector 0.0 0.0 1.0 #%b=[-3.14159265,3.14159265] #%q=7 #%a=11 +exposedField SFFloat thirdScaleCoordinate 0.0 #%b=[0,+I] #%q=0 #%a=7 +exposedField SFVec3f scaleOrientationVector 0.0 0.0 1.0 #%b=[-1,1] #%q=7 #%a=11 +exposedField SFFloat thirdTranslationCoordinate 0.0 #%b=[-I,+I] #%q=0 #%a=7 +exposedField SFRotation coordinateTransform 1.0 0.0 0.0 -1.5707963 #%b=[-3.14159265,3.14159265] #%q=10 +]{} + + +PROTO WideSound [ #%NDT=SFWorldNode,SF3DNode %COD=N +exposedField SFAudioNode source NULL +exposedField SFFloat intensity 1 #%b=[0,1] #%q=0 #%a=7 +exposedField SFVec3f location 0.0 0.0 0.0 #%b=[-I,+I] #%q=1 #%a=1 +exposedField SFBool spatialize TRUE +exposedField SFPerceptualParameterNode perceptualParameters NULL +exposedField SFBool roomEffect FALSE +exposedField SFInt32 shape 0 #%b=[0,4] #%q=13 4 +exposedField MFFloat size 0.0 #%b=[-I,+I] +exposedField SFVec3f direction 0.0 1.0 0.0 #%b=[-I,+I] #%q=9 #%a=9 +exposedField SFFloat density 0.5 #%b=[0,+I] +exposedField SFInt32 diffuseSelect 1 #%b=[0,+I] #%q=0 +exposedField SFFloat decorrStrength 1.0 #%b=[0,1] +field SFFloat speedOfSound 340.0 #%b=[0,+I] #%q=1 +field SFFloat distance 1000.0 #%b=[0,+I] #%q=0 +field SFBool useAirabs FALSE +]{} + diff --git a/applications/generators/MPEG4/templates8.txt b/applications/generators/MPEG4/templates8.txt new file mode 100644 index 0000000..2a907b2 --- /dev/null +++ b/applications/generators/MPEG4/templates8.txt @@ -0,0 +1,124 @@ +#-- Version 8 --# +# +# Beta for Symbolic Music Representation (SMR) +# +# templates for the BIFS nodes +# ============================= +# Notations I = Infinity +# %q=x Quantization method x +# 0 None +# 1 3D Position (SFVec3F) +# 2 2D Position (SFVec2F) +# 3 drawing Order +# 4 Color (SFColor) +# 5 Texture Coordinate +# 6 Angle (SFFloat 0-2PI) +# 7 Scale (SFVec2F or SFVec3F) +# 8 Interpolators keys +# 9 Normals +# 10 Rotations (SFRotation) +# 11 Object Size 3D (SFVec3F and SFFloat) +# 12 Object Size 2D +# 13 Linear Quantization (+ Nb Bits) +# 14 Index (of IndexedFaceSet,...) +# 15 SFVec4f +# 16 Reserved +# +# %a=y Animation method for fields that can be animated +# +## OO 081498 To match BIFS's update numbering +# 0 None +# 1 Position 3D +# 2 Position 2D +# 4 Color +# 6 Angle +# 7 Float +# 8 BoundFloat (intensities, transparencies,...) +# 9 Normal +# 10 Rotation +# 11 Size 3D +# 12 Size 2D +# 13 Integer +# 14 Reserved +## 0 3D Position +## 1 2D positon +## 2 Color (SFColor) +## 3 Angle (SFFloat 0-2pi) +## 4 Normals +## 5 Scale (SFVec2F) +## 6 Rotation (SFRotation) +## 7 Object Size or Scalar (SFFloat) +# +# %b=[min,max] bounds of value +# For each scalar or vectorial value, bounds may be specified. +# This will be used to check if user-specified values are out of bounds. In +# this case, bounds specified in the templates will be used (if not infinity). +# +# %NDT=Node Data Type +# For each node, one or several Node Data Types are assigned, specifying which node sub +# types the node belongs to. Moreover, each field of type SF/MF3DNode is re assigned +# a unique correct NodeDataType according to specify the allowed values of the field +# +# %COD Type of encoding +# N Normal Syntax : The node syntax follos the generic syntax for nodes +# S Special Syntax : The node has a specific syntax +# +# +# NCT => VRML type equivalence +# +# SF/MFxxxNode => SF/MFNode +# SF/MFURL => SF/MFString +# SF/MFCommandBuffer => SF/MFString +# SF/MFScript => SF/MFString +# +# +# Modification History +# ------------------------------------------------ +# October 9, 2006 [MBS] Added SMR nodes based on w8121 + +# +# Symbolic Music Representation (SMR) nodes +# + + +PROTO ScoreShape [ #%NDT=SFWorldNode,SF2DNode,SF3DNode %COD=N +exposedField SFMusicScoreNode score NULL +exposedField SF2DNode geometry NULL +]{} + + +PROTO MusicScore [ #%NDT=SFWorldNode,SFMusicScoreNode %COD=N +eventIn SFBool executeCommand +eventIn SFString gotoLabel +eventIn SFInt32 gotoMeasure +eventIn SFTime highlightTimePosition +eventIn SFVec3f mousePosition +exposedField MFString argumentsOnExecute [] +exposedField SFString commandOnExecute "" +exposedField SFInt32 firstVisibleMeasure 0 +exposedField SFBool hyperlinkEnable TRUE +exposedField SFBool loop FALSE +exposedField MFString partsLyrics [] +exposedField MFInt32 partsShown [] +exposedField SFTime scoreOffset 0.0 +exposedField SFVec2f size -1 -1 +exposedField SFFloat speed 1.0 #%b=(-I,+I) #%q=0 #%a=7 +exposedField SFTime startTime 0 #%b=(-I,+I) +exposedField SFTime stopTime 0 #%b=(-I,+I) +exposedField SFFloat transpose 0.0 +exposedField MFURL url [] +exposedField MFURL urlSA [] +exposedField SFString viewType "" +eventOut SFString activatedLink +eventOut MFString availableCommands +eventOut MFString availableLabels +eventOut MFString availableLyricLanguages +eventOut MFString availableViewTypes +eventOut SFBool isActive +eventOut SFVec3f highlightPosition +eventOut SFInt32 lastVisibleMeasure +eventOut SFInt32 numMeasures +eventOut MFString partNames +]{} + + diff --git a/applications/generators/MPEG4/templates9.txt b/applications/generators/MPEG4/templates9.txt new file mode 100644 index 0000000..16f86b4 --- /dev/null +++ b/applications/generators/MPEG4/templates9.txt @@ -0,0 +1,68 @@ +PROTO FootPrintSetNode [#%NDT=SFWorldNode,SF3DNode,SFGeometryNode %COD=N +exposedField MFGeometryNode children [] +]{} + +PROTO FootPrintNode [#%NDT=SFWorldNode,SF3DNode,SFGeometryNode %COD=N + +exposedField SFInt32 index -1 #%b=[0,65535] +exposedField SFGeometryNode footprint NULL +]{} + +PROTO BuildingPartNode [#%NDT=SFWorldNode,SF3DNode,SFGeometryNode %COD=N + +exposedField SFInt32 index -1 #%b=[0,65535] +exposedField SFGeometryNode footprint NULL +exposedField SFInt32 buildingIndex -1 #%b=[0,65535] +exposedField SFFloat height 0 #%b=[0,I] +exposedField SFFloat altitude 0 #%b=[0,I] +exposedField MFGeometryNode alternativeGeometry [] +exposedField MFGeometryNode roofs [] +exposedField MFGeometryNode facades [] +]{} + + + +PROTO RoofNode [#%NDT=SFWorldNode,SF3DNode,SFGeometryNode %COD=N + +exposedField SFInt32 Type 0 #%b=[0,65535] +exposedField SFFloat Height 0.0 #%b=[0,I] +exposedField MFFloat SlopeAngle [0.0] #%b=[0,6.2831854] +exposedField SFFloat EaveProjection 0.0 +exposedField SFInt32 EdgeSupportIndex -1 #%b=[0,65535] +exposedField SFURL RoofTextureURL "" +exposedField SFBool IsGenericTexture TRUE +exposedField SFFloat TextureXScale 1.0 #%b=[0,I] +exposedField SFFloat TextureYScale 1.0 #%b=[0,I] +exposedField SFFloat TextureXPosition 0.0 #%b=[0,I] +exposedField SFFloat TextureYPosition 0.0 #%b=[0,I] +exposedField SFFloat TextureRotation 0.0 #%b=[0,I] +]{} + + + +PROTO FacadeNode [#%NDT=SFWorldNode,SF3DNode,SFGeometryNode %COD=N +exposedField SFFloat WidthRatio 1.0 #%b=[-I,I] +exposedField SFFloat XScale 1.0 #%b=[-I,I] +exposedField SFFloat YScale 1.0 #%b=[-I,I] +exposedField SFFloat XPosition 0.0 #%b=[-I,I] +exposedField SFFloat YPosition 0.0 #%b=[-I,I] +exposedField SFFloat XRepeatInterval 0.0 #%b=[-I,I] +exposedField SFFloat YRepeatInterval 0.0 #%b=[-I,I] +exposedField SFBool Repeat FALSE +exposedField SFURL FacadePrimitive "" +exposedField SFInt32 NbStories 0 #%b=[0,65535] +exposedField MFInt32 NbFacadeCellsByStorey 0 +exposedField MFFloat StoreyHeight 1.0 #%b=[0,I] +exposedField MFGeometryNode FacadeCellsArray [] +]{} + + +PROTO Shadow [#%NDT=SFWorldNode,SF3DNode,SFGeometryNode %COD=N +eventIn SF3DNode addChildren +eventIn SF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFBool enabled TRUE +exposedField SFBool cast TRUE +exposedField SFBool receive TRUE +exposedField SFFloat penumbra 0 #%b=[0,I] +]{} diff --git a/applications/generators/Makefile b/applications/generators/Makefile new file mode 100644 index 0000000..820e257 --- /dev/null +++ b/applications/generators/Makefile @@ -0,0 +1,26 @@ +include ../../config.mak + +GENDIRS=MPEG4 X3D + +ifeq ($(HAS_LIBXML2), yes) +#sorry minGW friends, I can't get a stable libxml2 to compile ... +ifeq ($(CONFIG_WIN32), yes) +else +GENDIRS+=SVG +endif +endif + +all: sggen + +sggen: + set -e; for i in $(GENDIRS) ; do $(MAKE) -C $$i all; done + +dep: + set -e; for i in $(GENDIRS) ; do $(MAKE) -C $$i dep; done + +clean: + set -e; for i in $(GENDIRS) ; do $(MAKE) -C $$i clean; done + +distclean: + set -e; for i in $(GENDIRS) ; do $(MAKE) -C $$i distclean; done + diff --git a/applications/generators/SVG/Makefile b/applications/generators/SVG/Makefile new file mode 100644 index 0000000..53a8be6 --- /dev/null +++ b/applications/generators/SVG/Makefile @@ -0,0 +1,57 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/generators/SVG + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= html.o laser.o main.o v1.o v2.o v3.o + +CFLAGS+=-g +LDFLAGS+=-g +CFLAGS+=$(XML2_CFLAGS) + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=SVGGen$(EXE) +EXTRALIBS+=-lwsock32 -lz +else +EXT= +PROG=SVGGen +endif + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +SVGGen$(EXE): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(XML2_LIBS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac -lz + + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + + +clean: + rm -f $(OBJS) $(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/generators/SVG/SVGGen.dsp b/applications/generators/SVG/SVGGen.dsp new file mode 100644 index 0000000..c76b774 --- /dev/null +++ b/applications/generators/SVG/SVGGen.dsp @@ -0,0 +1,126 @@ +# Microsoft Developer Studio Project File - Name="SVGGen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=SVGGen - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SVGGen.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SVGGen.mak" CFG="SVGGen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SVGGen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "SVGGen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SVGGen - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libxml2.lib zlib.lib iconv.lib /nologo /subsystem:console /machine:I386 /libpath:"../../../extra_lib/lib/w32_release" + +!ELSEIF "$(CFG)" == "SVGGen - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include/" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libxml2.lib zlib.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "SVGGen - Win32 Release" +# Name "SVGGen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\utils\error.c +# End Source File +# Begin Source File + +SOURCE=.\html.c +# End Source File +# Begin Source File + +SOURCE=.\laser.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\utils\list.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +SOURCE=.\v1.c +# End Source File +# Begin Source File + +SOURCE=.\v2.c +# End Source File +# Begin Source File + +SOURCE=.\v3.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\svggen.h +# End Source File +# End Target +# End Project diff --git a/applications/generators/SVG/SVGGen.dsw b/applications/generators/SVG/SVGGen.dsw new file mode 100644 index 0000000..1b31b26 --- /dev/null +++ b/applications/generators/SVG/SVGGen.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SVGGen"=.\SVGGen.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.nvdl b/applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.nvdl new file mode 100644 index 0000000..0571331 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.nvdl @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.rng b/applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.rng new file mode 100644 index 0000000..90c7adc --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/Tiny-1.2.rng @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/animate.rng b/applications/generators/SVG/Tiny-1.2-NG/animate.rng new file mode 100644 index 0000000..5a49526 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/animate.rng @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + remove + freeze + + + + + + + + + + + + + + + + always + never + whenNotActive + + + + + + + + + + + + + + canSlip + locked + independent + default + + + + + + + + default + + + + + + + + + + + + + + + + + + + + canSlip + locked + independent + inherit + + + + + + + + inherit + + + + + + + + + + + + + + + + + + + + + XML + CSS + auto + + + + + + + + + + + + + + + discrete + linear + paced + spline + + + + + + + + + + + + + + + replace + sum + + + + + + + none + sum + + + + + + + + + + translate + scale + rotate + skewX + skewY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/animation-element.rng b/applications/generators/SVG/Tiny-1.2-NG/animation-element.rng new file mode 100644 index 0000000..8ef01ea --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/animation-element.rng @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/audio.rng b/applications/generators/SVG/Tiny-1.2-NG/audio.rng new file mode 100644 index 0000000..046f0de --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/audio.rng @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/conditional.rng b/applications/generators/SVG/Tiny-1.2-NG/conditional.rng new file mode 100644 index 0000000..03449a8 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/conditional.rng @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/contenttype-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/contenttype-attrib.rng new file mode 100644 index 0000000..b72188c --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/contenttype-attrib.rng @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/coordinate-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/coordinate-attrib.rng new file mode 100644 index 0000000..325982d --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/coordinate-attrib.rng @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/core-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/core-attrib.rng new file mode 100644 index 0000000..15cbdc1 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/core-attrib.rng @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + preserve + + + + + + + + + + + preserve + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/datatypes.rng b/applications/generators/SVG/Tiny-1.2-NG/datatypes.rng new file mode 100644 index 0000000..c330b2a --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/datatypes.rng @@ -0,0 +1,145 @@ + + + + + + + + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + self + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/discard.rng b/applications/generators/SVG/Tiny-1.2-NG/discard.rng new file mode 100644 index 0000000..18bd530 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/discard.rng @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/extensibility.rng b/applications/generators/SVG/Tiny-1.2-NG/extensibility.rng new file mode 100644 index 0000000..45309d7 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/extensibility.rng @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/extresources-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/extresources-attrib.rng new file mode 100644 index 0000000..f900756 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/extresources-attrib.rng @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/flowable-text-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/flowable-text-tiny.rng new file mode 100644 index 0000000..dc87152 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/flowable-text-tiny.rng @@ -0,0 +1,118 @@ + + + + + + + + + + + auto + before + center + after + inherit + + + + + + + auto + inherit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + + + + + + + + auto + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/focus-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/focus-attrib.rng new file mode 100644 index 0000000..edd10fc --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/focus-attrib.rng @@ -0,0 +1,86 @@ + + + + + + + + + + auto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + none + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/font-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/font-tiny.rng new file mode 100644 index 0000000..824006d --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/font-tiny.rng @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/gradient-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/gradient-tiny.rng new file mode 100644 index 0000000..a8cd97e --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/gradient-tiny.rng @@ -0,0 +1,156 @@ + + + + + + + + + + + inherit + + + + + + + + inherit + + + + + + + + + + + + + + + + + + + + + + userSpaceOnUse + objectBoundingBox + + + + + + + + + + + pad + reflect + repeat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/graphics-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/graphics-attrib.rng new file mode 100644 index 0000000..7b1028d --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/graphics-attrib.rng @@ -0,0 +1,109 @@ + + + + + + + + + + inline + block + list-item + run-in + compact + marker + table + inline-table + table-row-group + table-header-group + table-footer-group + table-row + table-column-group + table-column + table-cell + table-caption + none + inherit + + + + + + + visible + hidden + inherit + + + + + + + auto + optimizeSpeed + optimizeQuality + inherit + + + + + + + visiblePainted + visibleFill + visibleStroke + visible + painted + fill + stroke + all + none + inherit + + + + + + + auto + optimizeSpeed + crispEdges + geometricPrecision + inherit + + + + + + + auto + optimizeSpeed + optimizeLegibility + geometricPrecision + inherit + + + + + + + + + + whenStarted + always + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/handler.rng b/applications/generators/SVG/Tiny-1.2-NG/handler.rng new file mode 100644 index 0000000..f052fc9 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/handler.rng @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/headers.rng b/applications/generators/SVG/Tiny-1.2-NG/headers.rng new file mode 100644 index 0000000..a112936 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/headers.rng @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/hyperlink.rng b/applications/generators/SVG/Tiny-1.2-NG/hyperlink.rng new file mode 100644 index 0000000..a8e19e5 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/hyperlink.rng @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + _replace + _self + _parent + _top + _blank + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/image.rng b/applications/generators/SVG/Tiny-1.2-NG/image.rng new file mode 100644 index 0000000..1549ddb --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/image.rng @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/laser-ext.rng b/applications/generators/SVG/Tiny-1.2-NG/laser-ext.rng new file mode 100644 index 0000000..ed65b8a --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/laser-ext.rng @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/media-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/media-attrib.rng new file mode 100644 index 0000000..508dc45 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/media-attrib.rng @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + inherit + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/opacity-attrib-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/opacity-attrib-tiny.rng new file mode 100644 index 0000000..00fb018 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/opacity-attrib-tiny.rng @@ -0,0 +1,44 @@ + + + + + + + + + + inherit + + + + + + + + inherit + + + + + + + + + + + inherit + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/paint-attrib-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/paint-attrib-tiny.rng new file mode 100644 index 0000000..d67afaf --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/paint-attrib-tiny.rng @@ -0,0 +1,113 @@ + + + + + + + + + + inherit + + + + + + + + inherit + nonzero + evenodd + + + + + + + inherit + + + + + + + + inherit + none + + + + + + + + inherit + + + + + + + + butt + round + square + inherit + + + + + + + miter + round + bevel + inherit + + + + + + + inherit + + + + + + + + inherit + + + + + + + + inherit + + + + + + + + auto + optimizeSpeed + optimizeQuality + inherit + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/prefetch.rng b/applications/generators/SVG/Tiny-1.2-NG/prefetch.rng new file mode 100644 index 0000000..4f91049 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/prefetch.rng @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/script.rng b/applications/generators/SVG/Tiny-1.2-NG/script.rng new file mode 100644 index 0000000..65204fb --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/script.rng @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/shapes.rng b/applications/generators/SVG/Tiny-1.2-NG/shapes.rng new file mode 100644 index 0000000..1b32e93 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/shapes.rng @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/solidcolor.rng b/applications/generators/SVG/Tiny-1.2-NG/solidcolor.rng new file mode 100644 index 0000000..3e92662 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/solidcolor.rng @@ -0,0 +1,65 @@ + + + + + + + + + + + inherit + + + + + + + + inherit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/structure-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/structure-tiny.rng new file mode 100644 index 0000000..6bc021e --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/structure-tiny.rng @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \s*(none|xMidYMid)\s*(meet)?\s* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + disable + magnify + + + + + + + 1.0 + 1.1 + 1.2 + + + + + + + none + tiny + basic + full + + + + + + + + + + + + none + + + + + + + + onLoad + onStart + + + + + + + all + forwardOnly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/text-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/text-tiny.rng new file mode 100644 index 0000000..074bff0 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/text-tiny.rng @@ -0,0 +1,213 @@ + + + + + + + + + + + inherit + + + + + + + + inherit + + + + + + + + normal + italic + oblique + inherit + + + + + + + normal + small-caps + inherit + + + + + + + normal + bold + bolder + lighter + 100 + 200 + 300 + 400 + 500 + 600 + 700 + 800 + 900 + inherit + + + + + + + start + middle + end + inherit + + + + + + + start + center + end + inherit + + + + + + + none + underline + overline + line-through + blink + inherit + + + + + + + + + + + + + + + + + none + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/transform-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/transform-attrib.rng new file mode 100644 index 0000000..fe379ae --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/transform-attrib.rng @@ -0,0 +1,25 @@ + + + + + + + + + + + none + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/vectoreffects-attrib-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/vectoreffects-attrib-tiny.rng new file mode 100644 index 0000000..ed5c9ad --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/vectoreffects-attrib-tiny.rng @@ -0,0 +1,26 @@ + + + + + + + + + + none + non-scaling-stroke + inherit + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/video.rng b/applications/generators/SVG/Tiny-1.2-NG/video.rng new file mode 100644 index 0000000..b1f885d --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/video.rng @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + geometric + pinned + pinned90 + pinned180 + pinned270 + + + + + + + none + top + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/viewport-attrib-tiny.rng b/applications/generators/SVG/Tiny-1.2-NG/viewport-attrib-tiny.rng new file mode 100644 index 0000000..91473b2 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/viewport-attrib-tiny.rng @@ -0,0 +1,45 @@ + + + + + + + + + + inherit + none + + + + + + + + inherit + + + + + + + + visible + hidden + scroll + auto + inherit + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/xlink-attrib.rng b/applications/generators/SVG/Tiny-1.2-NG/xlink-attrib.rng new file mode 100644 index 0000000..83b4fb8 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/xlink-attrib.rng @@ -0,0 +1,123 @@ + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + onLoad + + + + + + + + other + + + + + + + + + embed + + + + + + + + + + + + + + + + + + + new + replace + + + + + + onRequest + + + + + + + + + + + + + + + diff --git a/applications/generators/SVG/Tiny-1.2-NG/xml-events.rng b/applications/generators/SVG/Tiny-1.2-NG/xml-events.rng new file mode 100644 index 0000000..147fed2 --- /dev/null +++ b/applications/generators/SVG/Tiny-1.2-NG/xml-events.rng @@ -0,0 +1,84 @@ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + default + capture + + + + + + + continue + stop + + + + + + + perform + cancel + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
diff --git a/applications/generators/SVG/html.c b/applications/generators/SVG/html.c new file mode 100644 index 0000000..6fdbbee --- /dev/null +++ b/applications/generators/SVG/html.c @@ -0,0 +1,151 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / SVG Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "svggen.h" +static FILE *BeginHtml() +{ + FILE *f; + char sPath[GF_MAX_PATH]; + + sprintf(sPath, "C:%cUsers%cCyril%ccontent%csvg%cregression%cregression_table.html", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + f = gf_fopen(sPath, "wt"); + + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "Status of the SVG implementation in GPAC\n"); + + { + time_t rawtime; + time(&rawtime); + fprintf(f, "\n\n", asctime(gmtime(&rawtime)), GPAC_VERSION); + } + fprintf(f, "\n", COPYRIGHT); + fprintf(f, "\n"); + + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "

Status of the SVG implementation in GPAC

\n"); + return f; +} + +static void EndHtml(FILE *f) +{ + fprintf(f, "\n"); + fprintf(f, "\n"); + gf_fclose(f); +} + +/* Generates an HTML table */ +void generate_table(GF_List *elements) +{ + u32 i, j; + u32 nbExamples = 0; + FILE *f; + f = BeginHtml(); + + + fprintf(f, "

Legend

\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "
StatusColor
Not supported
Partially supported
Fully supported
\n"); + + fprintf(f, "

SVG Tiny 1.2 Elements

\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + for (i = 0; i < gf_list_count(elements); i++) { + SVGGenElement *elt = gf_list_get(elements, i); + fprintf(f, "\n", elt->implementation_name); + fprintf(f, "\n", elt->svg_name, elt->svg_name); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + } + fprintf(f, "\n"); + fprintf(f, "
Element NameStatusObservationsExample(s)Bug(s)
%s   
\n"); + + for (i = 0; i < gf_list_count(elements); i++) { + SVGGenElement *elt = gf_list_get(elements, i); + fprintf(f, "

%s

\n", elt->implementation_name, elt->svg_name); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + for (j = 0; j < gf_list_count(elt->attributes); j++) { + SVGGenAttribute *att = gf_list_get(elt->attributes, j); + if (!strcmp(att->svg_name, "textContent")) continue; + fprintf(f, "\n"); + fprintf(f, "\n",att->svg_name); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n",++nbExamples); + fprintf(f, "\n"); + fprintf(f, "\n"); + } + fprintf(f, "\n"); + fprintf(f, "
Attribute NameStatusObservationsExample(s)Bug(s)
%s %d -   
\n"); + } + + EndHtml(f); + gf_list_del(elements); +} + diff --git a/applications/generators/SVG/laser.c b/applications/generators/SVG/laser.c new file mode 100644 index 0000000..3fc8a31 --- /dev/null +++ b/applications/generators/SVG/laser.c @@ -0,0 +1,267 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / SVG Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "svggen.h" + +static char *laser_attribute_name_type_list[] = { + "target", "accumulate", "additive", "audio_level", "bandwidth", "begin", "calcMode", "children", "choice", "clipBegin", "clipEnd", "color", "color_rendering", "cx", "cy", "d", "delta", "display", "display_align", "dur", "editable", "lsr_enabled", "end", "event", "externalResourcesRequired", "fill", "fill_opacity", "fill_rule", "focusable", "font_family", "font_size", "font_style", "font_variant", "font_weight", "fullscreen", "gradientUnits", "handler", "height", "image_rendering", "keyPoints", "keySplines", "keyTimes", "line_increment", "listener_target", "mediaCharacterEncoding", "mediaContentEncodings", "mediaSize", "mediaTime", "nav_down", "nav_down_left", "nav_down_right", "nav_left", "nav_next", "nav_prev", "nav_right", "nav_up", "nav_up_left", "nav_up_right", "observer", "offset", "opacity", "overflow", "overlay", "path", "pathLength", "pointer_events", "points", "preserveAspectRatio", "r", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "requiredFormats", "restart", "rotate", "rotation", "rx", "ry", "scale", "shape_rendering", "size", "solid_color", "solid_opacity", "stop_color", "stop_opacity", "stroke", "stroke_dasharray", "stroke_dashoffset", "stroke_linecap", "stroke_linejoin", "stroke_miterlimit", "stroke_opacity", "stroke_width", "svg_height", "svg_width", "syncBehavior", "syncBehaviorDefault", "syncReference", "syncTolerance", "syncToleranceDefault", "systemLanguage", "text_align", "text_anchor", "text_decoration", "text_display", "text_rendering", "textContent", "transform", "transformBehavior", "translation", "vector_effect", "viewBox", "viewport_fill", "viewport_fill_opacity", "visibility", "width", "x", "x1", "x2", "xlink_actuate", "xlink_arcrole", "xlink_href", "xlink_role", "xlink_show", "xlink_title", "xlink_type", "xml_base", "xml_lang", "y", "y1", "y2", "zoomAndPan", NULL +}; + + + +static char *laser_attribute_rare_type_list[] = { + "_class", "audio_level", "color", "color_rendering", "display", "display_align", "fill_opacity", + "fill_rule", "image_rendering", "line_increment", "pointer_events", "shape_rendering", "solid_color", + "solid_opacity", "stop_color", "stop_opacity", "stroke_dasharray", "stroke_dashoffset", "stroke_linecap", + "stroke_linejoin", "stroke_miterlimit", "stroke_opacity", "stroke_width", "text_anchor", "text_rendering", + "viewport_fill", "viewport_fill_opacity", "vector_effect", "visibility", "requiredExtensions", + "requiredFeatures", "requiredFormats", "systemLanguage", "xml_base", "xml_lang", "xml_space", + "nav_next", "nav_up", "nav_up_left", "nav_up_right", "nav_prev", "nav_down", "nav_down_left", + "nav_down_right", "nav_left", "focusable", "nav_right", "transform","text_decoration", + "extension", /*LASER EXTENSIONS SVG*/ + + "font_variant", "font_family", "font_size", "font_style", "font_weight", "xlink_title", "xlink_type", + "xlink_role", "xlink_arcrole", "xlink_actuate", "xlink_show", "end", "max", "min", + NULL +}; + + +s32 get_lsr_att_name_type(const char *name) +{ + u32 i = 0; + while (laser_attribute_name_type_list[i]) { + if (!strcmp(name, laser_attribute_name_type_list[i])) return i; + i++; + } + return -1; +} + +void generateGenericAttrib(FILE *output, SVGGenElement *elt, u32 index) +{ + int k; + for (k=0; k < generic_attributes[index].array_length; k++) { + char *att_name = generic_attributes[index].array[k]; + SVGGenAttribute *a = findAttribute(elt, att_name); + if (a) { + s32 type = get_lsr_att_name_type(att_name); + /*SMIL anim fill not updatable*/ + if ((index==6) && !strcmp(att_name, "fill")) { + type = -1; + } + fprintf(output, ", %d", type); + } + } +} + +void generate_laser_tables(GF_List *svg_elements) +{ + FILE *output; + u32 i; + u32 special_cases; + + output = BeginFile(2); + if (generation_mode == 1) fprintf(output, "\n#include \n\n"); + else if (generation_mode == 2) fprintf(output, "\n#include \n\n"); + else if (generation_mode == 3) fprintf(output, "\n#include \n\n"); + + for (i=0; iattributes); + + fprintf(output, "static const s32 %s_field_to_attrib_type[] = {\n", elt->implementation_name); + + /*core info: id, xml:id, class, xml:lang, xml:base, xml:space, externalResourcesRequired*/ + fprintf(output, "-1, -1, -1, 125, 124, -1, 24"); + if (elt->has_media_properties) generateGenericAttrib(output, elt, 2); + if (elt->has_properties) generateGenericAttrib(output, elt, 1); + if (elt->has_opacity_properties) generateGenericAttrib(output, elt, 3); + if (elt->has_focus) generateGenericAttrib(output, elt, 4); + if (elt->has_xlink) generateGenericAttrib(output, elt, 5); + if (elt->has_timing) generateGenericAttrib(output, elt, 6); + if (elt->has_sync) generateGenericAttrib(output, elt, 7); + if (elt->has_animation) generateGenericAttrib(output, elt, 8); + if (elt->has_conditional) generateGenericAttrib(output, elt, 9); + /*WATCHOUT - HARDCODED VALUES*/ + if (elt->has_transform) fprintf(output, ", 105"); + if (elt->has_xy) fprintf(output, ", 116, 129"); + + + /*svg.width and svg.height escapes*/ + special_cases = 0; + if (!strcmp(elt->svg_name, "svg")) special_cases = 1; + else if (!strcmp(elt->svg_name, "a")) special_cases = 2; + + for (j=0; jattributes, j); + s32 type = get_lsr_att_name_type(att->svg_name); + if (special_cases==1) { + if (!strcmp(att->svg_name, "width")) + type = 95; + else if (!strcmp(att->svg_name, "height")) + type = 94; + } + if ((special_cases==2) && !strcmp(att->svg_name, "target")) + type = 0; + fprintf(output, ", %d", type); + } + fprintf(output, "\n};\n\n"); + + } + fprintf(output, "s32 gf_lsr_field_to_attrib_type(GF_Node *n, u32 fieldIndex)\n{\n\tif(!n) return -2;\n\tswitch (gf_node_get_tag(n)) {\n"); + for (i=0; iimplementation_name); + fcount = gf_list_count(elt->attributes); + fprintf(output, "\t\treturn %s_field_to_attrib_type[fieldIndex];\n", elt->implementation_name); + } + fprintf(output, "\tdefault:\n\t\treturn -2;\n\t}\n}\n\n"); +} + + +void generate_laser_tables_da(GF_List *atts) +{ + FILE *output; + u32 i, count, j, count2; + + output = BeginFile(2); + + fprintf(output, "\n#include \n\n"); + fprintf(output, "\n\ns32 gf_lsr_anim_type_from_attribute(u32 tag) {\n\tswitch(tag) {\n"); + + count = gf_list_count(atts); + j=0; + while (laser_attribute_name_type_list[j]) { + for (i=0; iimplementation_name, laser_attribute_name_type_list[j])) { + fprintf(output, "\tcase TAG_SVG_ATT_%s: return %d;\n", att->implementation_name, j); + break; + } + } + if (i==count) { + //fprintf(stdout, "Warning: Ignoring %s\n", laser_attribute_name_type_list[j]); + fprintf(output, "\tcase TAG_LSR_ATT_%s: return %d;\n", laser_attribute_name_type_list[j], j); + } + j++; + } + fprintf(output, "\tdefault: return -1;\n\t}\n}\n\n"); + + fprintf(output, "\n\ns32 gf_lsr_rare_type_from_attribute(u32 tag) {\n\tswitch(tag) {\n"); + count = gf_list_count(atts); + j=0; + while (laser_attribute_rare_type_list[j]) { + for (i=0; iimplementation_name, laser_attribute_rare_type_list[j])) { + fprintf(output, "\tcase TAG_SVG_ATT_%s: return %d;\n", att->implementation_name, j); + break; + } + } + if (i==count) { + if (!strcmp(laser_attribute_rare_type_list[j], "extension")) { + fprintf(output, "\tcase TAG_SVG_ATT_syncMaster: return %d;\n", j); + fprintf(output, "\tcase TAG_SVG_ATT_focusHighlight: return %d;\n", j); + fprintf(output, "\tcase TAG_SVG_ATT_initialVisibility: return %d;\n", j); + fprintf(output, "\tcase TAG_SVG_ATT_fullscreen: return %d;\n", j); + fprintf(output, "\tcase TAG_SVG_ATT_requiredFonts: return %d;\n", j); + } else { + fprintf(stdout, "Warning: Ignoring %s\n", laser_attribute_rare_type_list[j]); + } + } + j++; + } + fprintf(output, "\tdefault: return -1;\n\t}\n}\n\n"); + + + + fprintf(output, "\n\ns32 gf_lsr_anim_type_to_attribute(u32 tag) {\n\tswitch(tag) {\n"); + j=0; + while (laser_attribute_name_type_list[j]) { + for (i=0; iimplementation_name, laser_attribute_name_type_list[j])) { + fprintf(output, "\tcase %d: return TAG_SVG_ATT_%s;\n", j, att->implementation_name); + break; + } + } + if (i==count) { + fprintf(output, "\tcase %d: return TAG_LSR_ATT_%s;\n", j, laser_attribute_name_type_list[j]); + } + j++; + } + fprintf(output, "\tdefault: return -1;\n\t}\n}\n\n"); + + fprintf(output, "\n\ns32 gf_lsr_rare_type_to_attribute(u32 tag) {\n\tswitch(tag) {\n"); + j=0; + while (laser_attribute_rare_type_list[j]) { + for (i=0; iimplementation_name, laser_attribute_rare_type_list[j])) { + fprintf(output, "\tcase %d: return TAG_SVG_ATT_%s;\n", j, att->implementation_name); + break; + } + } + j++; + } + fprintf(output, "\tdefault: return -1;\n\t}\n}\n\n"); + + + fprintf(output, "\n\nu32 gf_lsr_same_rare(SVGAllAttributes *elt_atts, SVGAllAttributes *base_atts)\n{\n"); + fprintf(output, "\tGF_FieldInfo f_elt, f_base;\n"); + + j=0; + while (laser_attribute_rare_type_list[j]) { + SVGGenAttribute *att = NULL; + if (!strcmp(laser_attribute_rare_type_list[j], "extension")) { + j++; + continue; + } + for (i=0; iimplementation_name, laser_attribute_rare_type_list[j])) + break; + att = NULL; + } + assert(att); + + fprintf(output, "\tf_elt.fieldType = f_base.fieldType = %s_datatype;\n", att->impl_type); + fprintf(output, "\tf_elt.fieldIndex = f_base.fieldIndex = TAG_SVG_ATT_%s;\n", laser_attribute_rare_type_list[j]); + fprintf(output, "\tf_elt.far_ptr = elt_atts->%s;\n", laser_attribute_rare_type_list[j]); + fprintf(output, "\tf_base.far_ptr = base_atts->%s;\n", laser_attribute_rare_type_list[j]); + fprintf(output, "\tif (!gf_svg_attributes_equal(&f_elt, &f_base)) return 0;\n\n"); + + j++; + } + fprintf(output, "\treturn 1;\n}\n\n"); + + gf_fclose(output); +} \ No newline at end of file diff --git a/applications/generators/SVG/main.c b/applications/generators/SVG/main.c new file mode 100644 index 0000000..3a393d8 --- /dev/null +++ b/applications/generators/SVG/main.c @@ -0,0 +1,953 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / SVG Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "svggen.h" + +SVGGenAttribute *NewSVGGenAttribute() +{ + SVGGenAttribute *att; + GF_SAFEALLOC(att, SVGGenAttribute) + return att; +} + +void deleteSVGGenAttribute(SVGGenAttribute **p) +{ + xmlFree((*p)->svg_name); + xmlFree((*p)->svg_type); + gf_free(*p); + *p = NULL; +} + +SVGGenAttrGrp *NewSVGGenAttrGrp() +{ + SVGGenAttrGrp *tmp; + GF_SAFEALLOC(tmp, SVGGenAttrGrp) + tmp->attrs = gf_list_new(); + tmp->attrgrps = gf_list_new(); + return tmp; +} + +SVGGenElement *NewSVGGenElement() +{ + SVGGenElement *elt; + GF_SAFEALLOC(elt, SVGGenElement); + if (elt) { + elt->attributes = gf_list_new(); + elt->generic_attributes = gf_list_new(); + } + return elt; +} + +void deleteSVGGenElement(SVGGenElement **p) +{ + u32 i; + xmlFree((*p)->svg_name); + for (i = 0; i < gf_list_count((*p)->attributes); i++) { + SVGGenAttribute *a = gf_list_get((*p)->attributes, i); + deleteSVGGenAttribute(&a); + } + gf_list_del((*p)->attributes); + gf_free(*p); + *p = NULL; +} + +static GF_List *sortElements(GF_List *elements) +{ + u32 i, j; + GF_List *sorted_elements = gf_list_new(); + + for (i = 0; i< gf_list_count(elements); i++) { + u8 is_added = 0; + SVGGenElement *elt = gf_list_get(elements, i); + for (j = 0; j < gf_list_count(sorted_elements); j++) { + SVGGenElement *selt = gf_list_get(sorted_elements, j); + if (strcmp(elt->svg_name, selt->svg_name) < 0) { + gf_list_insert(sorted_elements, elt, j); + is_added = 1; + break; + } + } + if (!is_added) gf_list_add(sorted_elements, elt); + } + + gf_list_del(elements); + return sorted_elements; +} + +static GF_List *sortAttrGrp(GF_List *attgrps) +{ + u32 i, j; + GF_List *sorted_attgrps = gf_list_new(); + + for (i = 0; i< gf_list_count(attgrps); i++) { + u8 is_added = 0; + SVGGenAttrGrp *grp = gf_list_get(attgrps, i); + for (j = 0; j < gf_list_count(sorted_attgrps); j++) { + SVGGenAttrGrp *sgrp = gf_list_get(sorted_attgrps, j); + if (strcmp(grp->name, sgrp->name) < 0) { + gf_list_insert(sorted_attgrps, grp, j); + is_added = 1; + break; + } + } + if (!is_added) gf_list_add(sorted_attgrps, grp); + } + + gf_list_del(attgrps); + return sorted_attgrps; +} + +static GF_List *sortAttr(GF_List *atts) +{ + u32 i, j; + GF_List *sorted_atts = gf_list_new(); + + for (i = 0; i< gf_list_count(atts); i++) { + u8 is_added = 0; + SVGGenAttribute *att = gf_list_get(atts, i); + for (j = 0; j < gf_list_count(sorted_atts); j++) { + SVGGenAttribute *satt = gf_list_get(sorted_atts, j); + if (strcmp(att->svg_name, satt->svg_name) < 0) { + gf_list_insert(sorted_atts, att, j); + is_added = 1; + break; + } + } + if (!is_added) gf_list_add(sorted_atts, att); + } + + gf_list_del(atts); + return sorted_atts; +} + +void svgNameToImplementationName(xmlChar *svg_name, char implementation_name[50]) { + char *tmp; + strcpy(implementation_name, svg_name); + tmp = implementation_name; + while ( (tmp = strchr(tmp, '.')) ) { + *tmp='_'; + tmp++; + } + tmp = implementation_name; + while ( (tmp = strchr(tmp, '-')) ) { + *tmp='_'; + tmp++; + } + tmp = implementation_name; + while ( (tmp = strchr(tmp, ':')) ) { + *tmp='_'; + tmp++; + } +} + +static Bool isGenericAttributesGroup(char *name) +{ + if (!strcmp(name, "svg.Core.attr") || + !strcmp(name, "svg.CorePreserve.attr") || + !strcmp(name, "svg.External.attr") || + !strcmp(name, "svg.Properties.attr") || + !strcmp(name, "svg.Media.attr") || + !strcmp(name, "svg.MediaClip.attr") || + !strcmp(name, "svg.Opacity.attr") || + !strcmp(name, "svg.FocusHighlight.attr") || + !strcmp(name, "svg.Focus.attr") || + !strcmp(name, "svg.AnimateCommon.attr") || + !strcmp(name, "svg.XLinkEmbed.attr") || + !strcmp(name, "svg.XLinkRequired.attr") || + !strcmp(name, "svg.XLinkReplace.attr") || +// !strcmp(name, "svg.ContentType.attr") || + !strcmp(name, "svg.AnimateTiming.attr") || + !strcmp(name, "svg.AnimateTimingNoMinMax.attr") || + !strcmp(name, "svg.AnimateBegin.attr") || + !strcmp(name, "svg.AnimateTimingNoFillNoMinMax.attr") || + !strcmp(name, "svg.AnimateSync.attr") || + !strcmp(name, "svg.AnimateSyncDefault.attr") || + !strcmp(name, "svg.AnimateAttributeCommon.attr") || + !strcmp(name, "svg.AnimateToCommon.attr") || + !strcmp(name, "svg.AnimateValueCommon.attr") || + !strcmp(name, "svg.AnimateAdditionCommon.attr") || + !strcmp(name, "svg.AnimateTypeCommon.attr") || + !strcmp(name, "svg.Conditional.attr") || +// !strcmp(name, "svg.XY.attr") || + !strcmp(name, "svg.Transform.attr")) { + return 1; + } else { + return 0; + } +} + +static Bool setGenericAttributesFlags(char *name, SVGGenElement *e) +{ + Bool ret = 1; + if (!strcmp(name, "svg.Core.attr") || + !strcmp(name, "svg.CorePreserve.attr") || + !strcmp(name, "svg.External.attr")) { + e->has_svg_generic = 1; + e->has_xml_generic = 1; + } else if (!strcmp(name, "svg.Properties.attr")) { + e->has_properties = 1; + e->has_media_properties = 1; + } else if (!strcmp(name, "svg.Media.attr")) { + e->has_media_properties = 1; + } else if (!strcmp(name, "svg.Opacity.attr")) { + e->has_opacity_properties = 1; + } else if (!strcmp(name, "svg.FocusHighlight.attr") || + !strcmp(name, "svg.Focus.attr")) { + e->has_focus = 1; + } else if (!strcmp(name, "svg.AnimateCommon.attr") || + !strcmp(name, "svg.XLinkEmbed.attr") || + !strcmp(name, "svg.XLinkRequired.attr") || + !strcmp(name, "svg.XLinkReplace.attr")) { //|| +// !strcmp(name, "svg.ContentType.attr")) { + e->has_xlink = 1; + } else if (!strcmp(name, "svg.AnimateTiming.attr") || + !strcmp(name, "svg.AnimateTimingNoMinMax.attr") || + !strcmp(name, "svg.AnimateBegin.attr") || + !strcmp(name, "svg.AnimateTimingNoFillNoMinMax.attr")) { + e->has_timing = 1; + } else if (!strcmp(name, "svg.AnimateSync.attr") || + !strcmp(name, "svg.AnimateSyncDefault.attr")) { + e->has_sync= 1; + } else if (!strcmp(name, "svg.AnimateAttributeCommon.attr") || + !strcmp(name, "svg.AnimateToCommon.attr") || + !strcmp(name, "svg.AnimateValueCommon.attr") || + !strcmp(name, "svg.AnimateAdditionCommon.attr") || + !strcmp(name, "svg.AnimateTypeCommon.attr")) { + e->has_animation = 1; + } else if (!strcmp(name, "svg.Conditional.attr")) { + e->has_conditional = 1; + } else if (!strcmp(name, "svg.Transform.attr")) { + e->has_transform = 1; + } else if (!strcmp(name, "svg.XY.attr")) { + e->has_xy = 1; + } else { + ret = 0; + } + return ret; +} + +static void flattenAttributeGroup(SVGGenAttrGrp attgrp, SVGGenElement *e, Bool all); + +static void flattenAttributeGroups(GF_List *attrgrps, SVGGenElement *e, Bool all) +{ + u32 i; + for (i = 0; i < gf_list_count(attrgrps); i ++) { + SVGGenAttrGrp *ag = gf_list_get(attrgrps, i); + flattenAttributeGroup(*ag, e, all); + } +} + +static void flattenAttributeGroup(SVGGenAttrGrp attgrp, SVGGenElement *e, Bool all) +{ + u32 i; + + if (isGenericAttributesGroup(attgrp.name) && !all) { + setGenericAttributesFlags(attgrp.name, e); + flattenAttributeGroups(attgrp.attrgrps, e, 1); + for (i = 0; i < gf_list_count(attgrp.attrs); i++) { + gf_list_add(e->generic_attributes, gf_list_get(attgrp.attrs, i)); + } + } else { + flattenAttributeGroups(attgrp.attrgrps, e, all); + for (i = 0; i < gf_list_count(attgrp.attrs); i++) { + if (all) + gf_list_add(e->generic_attributes, gf_list_get(attgrp.attrs, i)); + else + gf_list_add(e->attributes, gf_list_get(attgrp.attrs, i)); + } + } +} + +SVGGenAttribute *findAttribute(SVGGenElement *e, char *name) +{ + u32 i; + for (i = 0; i < gf_list_count(e->attributes); i++) { + SVGGenAttribute *a = gf_list_get(e->attributes, i); + if (!strcmp(a->svg_name, name)) return a; + } + for (i = 0; i < gf_list_count(e->generic_attributes); i++) { + SVGGenAttribute *a = gf_list_get(e->generic_attributes, i); + if (!strcmp(a->svg_name, name)) return a; + } + return NULL; +} + +static u32 countAttributesAllInGroup(SVGGenAttrGrp *ag) +{ + u32 i, ret = 0; + for (i = 0; i < gf_list_count(ag->attrgrps); i ++) { + SVGGenAttrGrp *agtmp = gf_list_get(ag->attrgrps, i); + ret += countAttributesAllInGroup(agtmp); + } + ret += gf_list_count(ag->attrs); + return ret; +} + +/* XML related functions */ +xmlNodeSetPtr findNodes( xmlXPathContextPtr ctxt, xmlChar * path ) +{ + xmlXPathObjectPtr res = NULL; + + if ( ctxt->node != NULL && path != NULL ) { + xmlXPathCompExprPtr comp; + + xmlDocPtr tdoc = NULL; + xmlNodePtr froot = ctxt->node; + + comp = xmlXPathCompile( path ); + if ( comp == NULL ) { + return NULL; + } + + if ( ctxt->node->doc == NULL ) { + /* if one XPaths a node from a fragment, libxml2 will + refuse the lookup. this is not very usefull for XML + scripters. thus we need to create a temporary document + to make libxml2 do it's job correctly. + */ + tdoc = xmlNewDoc( NULL ); + + /* find refnode's root node */ + while ( froot != NULL ) { + if ( froot->parent == NULL ) { + break; + } + froot = froot->parent; + } + xmlAddChild((xmlNodePtr)tdoc, froot); + + ctxt->node->doc = tdoc; + } + + res = xmlXPathCompiledEval(comp, ctxt); + + xmlXPathFreeCompExpr(comp); + + if ( tdoc != NULL ) { + /* after looking through a fragment, we need to drop the + fake document again */ + xmlSetTreeDoc(froot,NULL); + froot->doc = NULL; + tdoc->children = NULL; + tdoc->last = NULL; + froot->parent = NULL; + ctxt->node->doc = NULL; + + xmlFreeDoc( tdoc ); + } + } + if (res && res->type == XPATH_NODESET) + return res->nodesetval; + else + return NULL; +} + + +/* definition of GPAC groups of SVG attributes */ + +void setAttributeType(SVGGenAttribute *att) +{ + if (!att->svg_type) { /* if the type is not given in the RNG, we explicitely set it */ + if (!strcmp(att->svg_name, "textContent")) { + strcpy(att->impl_type, "SVG_TextContent"); + } else if (!strcmp(att->svg_name, "class")) { + strcpy(att->implementation_name, "_class"); + strcpy(att->impl_type, "SVG_String"); + } else if (!strcmp(att->svg_name, "visibility")) { + strcpy(att->impl_type, "SVG_Visibility"); + } else if (!strcmp(att->svg_name, "display")) { + strcpy(att->impl_type, "SVG_Display"); + } else if (!strcmp(att->svg_name, "stroke-linecap")) { + strcpy(att->impl_type, "SVG_StrokeLineCap"); + } else if (!strcmp(att->svg_name, "stroke-dasharray")) { + strcpy(att->impl_type, "SVG_StrokeDashArray"); + } else if (!strcmp(att->svg_name, "stroke-linejoin")) { + strcpy(att->impl_type, "SVG_StrokeLineJoin"); + } else if (!strcmp(att->svg_name, "font-style")) { + strcpy(att->impl_type, "SVG_FontStyle"); + } else if (!strcmp(att->svg_name, "font-weight")) { + strcpy(att->impl_type, "SVG_FontWeight"); + } else if (!strcmp(att->svg_name, "text-anchor")) { + strcpy(att->impl_type, "SVG_TextAnchor"); + } else if (!strcmp(att->svg_name, "fill")) { + strcpy(att->impl_type, "SMIL_Fill"); + } else if (!strcmp(att->svg_name, "fill-rule")) { + strcpy(att->impl_type, "SVG_FillRule"); + } else if (!strcmp(att->svg_name, "font-family")) { + strcpy(att->impl_type, "SVG_FontFamily"); + } else if (!strcmp(att->svg_name, "calcMode")) { + strcpy(att->impl_type, "SMIL_CalcMode"); + } else if (!strcmp(att->svg_name, "values")) { + strcpy(att->impl_type, "SMIL_AnimateValues"); + } else if (!strcmp(att->svg_name, "keyTimes")) { + strcpy(att->impl_type, "SMIL_KeyTimes"); + } else if (!strcmp(att->svg_name, "keySplines")) { + strcpy(att->impl_type, "SMIL_KeySplines"); + } else if (!strcmp(att->svg_name, "keyPoints")) { + strcpy(att->impl_type, "SMIL_KeyPoints"); + } else if (!strcmp(att->svg_name, "from") || + !strcmp(att->svg_name, "to") || + !strcmp(att->svg_name, "by")) { + strcpy(att->impl_type, "SMIL_AnimateValue"); + } else if (!strcmp(att->svg_name, "additive")) { + strcpy(att->impl_type, "SMIL_Additive"); + } else if (!strcmp(att->svg_name, "accumulate")) { + strcpy(att->impl_type, "SMIL_Accumulate"); + } else if (!strcmp(att->svg_name, "begin") || + !strcmp(att->svg_name, "end") + ) { + strcpy(att->impl_type, "SMIL_Times"); + } else if (!strcmp(att->svg_name, "clipBegin") || + !strcmp(att->svg_name, "clipEnd") + ) { + strcpy(att->impl_type, "SVG_Clock"); + } else if (!strcmp(att->svg_name, "min") || + !strcmp(att->svg_name, "max") || + !strcmp(att->svg_name, "dur") || + !strcmp(att->svg_name, "repeatDur") + ) { + strcpy(att->impl_type, "SMIL_Duration"); + } else if (!strcmp(att->svg_name, "repeat")) { + strcpy(att->impl_type, "SMIL_Repeat"); + } else if (!strcmp(att->svg_name, "restart")) { + strcpy(att->impl_type, "SMIL_Restart"); + } else if (!strcmp(att->svg_name, "repeatCount")) { + strcpy(att->impl_type, "SMIL_RepeatCount"); + } else if (!strcmp(att->svg_name, "attributeName")) { + strcpy(att->impl_type, "SMIL_AttributeName"); + } else if (!strcmp(att->svg_name, "type")) { + strcpy(att->impl_type, "SVG_TransformType"); + } else if (!strcmp(att->svg_name, "font-size")) { + strcpy(att->impl_type, "SVG_FontSize"); + } else if (!strcmp(att->svg_name, "viewBox")) { + strcpy(att->impl_type, "SVG_ViewBox"); + } else if (!strcmp(att->svg_name, "preserveAspectRatio")) { + strcpy(att->impl_type, "SVG_PreserveAspectRatio"); + } else if (!strcmp(att->svg_name, "zoomAndPan")) { + strcpy(att->impl_type, "SVG_ZoomAndPan"); + } else if (!strcmp(att->svg_name, "path")) { + strcpy(att->impl_type, "SVG_PathData"); + } else if (!strcmp(att->svg_name, "image-rendering")) { + strcpy(att->impl_type, "SVG_RenderingHint"); + } else if (!strcmp(att->svg_name, "color-rendering")) { + strcpy(att->impl_type, "SVG_RenderingHint"); + } else if (!strcmp(att->svg_name, "text-rendering")) { + strcpy(att->impl_type, "SVG_RenderingHint"); + } else if (!strcmp(att->svg_name, "shape-rendering")) { + strcpy(att->impl_type, "SVG_RenderingHint"); + } else if (!strcmp(att->svg_name, "pointer-events")) { + strcpy(att->impl_type, "SVG_PointerEvents"); + } else if (!strcmp(att->svg_name, "vector-effect")) { + strcpy(att->impl_type, "SVG_VectorEffect"); + } else if (!strcmp(att->svg_name, "vector-effect")) { + strcpy(att->impl_type, "SVG_VectorEffect"); + } else if (!strcmp(att->svg_name, "display-align")) { + strcpy(att->impl_type, "SVG_DisplayAlign"); + } else if (!strcmp(att->svg_name, "text-align")) { + strcpy(att->impl_type, "SVG_TextAlign"); + } else if (!strcmp(att->svg_name, "propagate")) { + strcpy(att->impl_type, "XMLEV_Propagate"); + } else if (!strcmp(att->svg_name, "defaultAction")) { + strcpy(att->impl_type, "XMLEV_DefaultAction"); + } else if (!strcmp(att->svg_name, "phase")) { + strcpy(att->impl_type, "XMLEV_Phase"); + } else if (!strcmp(att->svg_name, "syncBehavior")) { + strcpy(att->impl_type, "SMIL_SyncBehavior"); + } else if (!strcmp(att->svg_name, "syncBehaviorDefault")) { + strcpy(att->impl_type, "SMIL_SyncBehavior"); + } else if (!strcmp(att->svg_name, "attributeType")) { + strcpy(att->impl_type, "SMIL_AttributeType"); + } else if (!strcmp(att->svg_name, "playbackOrder")) { + strcpy(att->impl_type, "SVG_PlaybackOrder"); + } else if (!strcmp(att->svg_name, "timelineBegin")) { + strcpy(att->impl_type, "SVG_TimelineBegin"); + } else if (!strcmp(att->svg_name, "xml:space")) { + strcpy(att->impl_type, "XML_Space"); + } else if (!strcmp(att->svg_name, "snapshotTime")) { + strcpy(att->impl_type, "SVG_Clock"); + } else if (!strcmp(att->svg_name, "version")) { + strcpy(att->impl_type, "SVG_String"); + } else if (!strcmp(att->svg_name, "gradientUnits")) { + strcpy(att->impl_type, "SVG_GradientUnit"); + } else if (!strcmp(att->svg_name, "baseProfile")) { + strcpy(att->impl_type, "SVG_String"); + } else if (!strcmp(att->svg_name, "focusHighlight")) { + strcpy(att->impl_type, "SVG_FocusHighlight"); + } else if (!strcmp(att->svg_name, "initialVisibility")) { + strcpy(att->impl_type, "SVG_InitialVisibility"); + } else if (!strcmp(att->svg_name, "overlay")) { + strcpy(att->impl_type, "SVG_Overlay"); + } else if (!strcmp(att->svg_name, "transformBehavior")) { + strcpy(att->impl_type, "SVG_TransformBehavior"); + } else if (!strcmp(att->svg_name, "rotate")) { + strcpy(att->impl_type, "SVG_Rotate"); + } else if (!strcmp(att->svg_name, "font-variant")) { + strcpy(att->impl_type, "SVG_FontVariant"); + } else if (!strcmp(att->svg_name, "lsr:enabled")) { + strcpy(att->impl_type, "SVG_Boolean"); + } else if (!strcmp(att->svg_name, "spreadMethod")) { + strcpy(att->impl_type, "SVG_SpreadMethod"); + } else if (!strcmp(att->svg_name, "gradientTransform")) { + strcpy(att->impl_type, "SVG_Transform_Full"); + } else if (!strcmp(att->svg_name, "editable")) { + strcpy(att->impl_type, "SVG_Boolean"); + } else if (!strcmp(att->svg_name, "choice")) { + strcpy(att->impl_type, "LASeR_Choice"); + } else if (!strcmp(att->svg_name, "size") || + !strcmp(att->svg_name, "delta")) { + strcpy(att->impl_type, "LASeR_Size"); + } else if (!strcmp(att->svg_name, "syncReference")) { + strcpy(att->impl_type, "XMLRI"); + } else { + /* For all other attributes, we use String as default type */ + strcpy(att->impl_type, "SVG_String"); + fprintf(stdout, "Warning: using type SVG_String for attribute %s.\n", att->svg_name); + } + } else { /* for some attributes, the type given in the RNG needs to be overriden */ + if (!strcmp(att->svg_name, "color")) { + strcpy(att->impl_type, "SVG_Paint"); + } else if (!strcmp(att->svg_name, "viewport-fill")) { + strcpy(att->impl_type, "SVG_Paint"); + } else if (!strcmp(att->svg_name, "syncTolerance")) { + strcpy(att->impl_type, "SMIL_SyncTolerance"); + } else if (!strcmp(att->svg_name, "syncToleranceDefault")) { + strcpy(att->impl_type, "SMIL_SyncTolerance"); + } else if (!strcmp(att->svg_name, "transform")) { + strcpy(att->impl_type, "SVG_Transform"); + } else if (!strcmp(att->svg_name, "gradientTransform")) { + strcpy(att->impl_type, "SVG_Transform"); + } else if (!strcmp(att->svg_name, "focusable")) { + strcpy(att->impl_type, "SVG_Focusable"); + } else if (!strcmp(att->svg_name, "event") || !strcmp(att->svg_name, "ev:event")) { + strcpy(att->impl_type, "XMLEV_Event"); + } else if (!strcmp(att->svg_type, "IRI.datatype")) { + strcpy(att->impl_type, "XMLRI"); + } else if (!strcmp(att->svg_type, "IDREF.datatype")) { + strcpy(att->impl_type, "XML_IDREF"); + } else if (strstr(att->svg_type, "datatype")) { + char *tmp; + sprintf(att->impl_type, "SVG_%s", att->svg_type); + tmp = att->impl_type; + while ( (tmp = strstr(tmp, "-")) ) { + *tmp='_'; + tmp++; + } + tmp = att->impl_type; + while ( (tmp = strstr(tmp, ".")) ) { + *tmp='_'; + tmp++; + } + tmp = att->impl_type;; + if ( (tmp = strstr(tmp, "datatype")) ) { + tmp--; + *tmp = 0; + } + } + } +} + +void getAttributeType(xmlDocPtr doc, xmlXPathContextPtr xpathCtx, + xmlNodePtr attributeNode, SVGGenAttribute *a) +{ + + xmlNodeSetPtr refNodes; + xpathCtx->node = attributeNode; + refNodes = findNodes(xpathCtx, ".//rng:ref"); + if (refNodes->nodeNr == 0) { + //a->svg_type = xmlStrdup("0_ref_type"); + } else if (refNodes->nodeNr == 1) { + xmlNodePtr ref = refNodes->nodeTab[0]; + a->svg_type = xmlStrdup(xmlGetProp(ref, "name")); + } else { + //a->svg_type = xmlStrdup("N_ref_type"); + } +} + +void getRealAttributes(xmlDocPtr doc, xmlXPathContextPtr xpathCtx, xmlNodePtr newCtxNode, + GF_List *attributes) +{ + xmlNodeSetPtr attributeNodes; + int k; + u32 j; + + xpathCtx->node = newCtxNode; + attributeNodes = findNodes(xpathCtx, ".//rng:attribute"); + for (k = 0; k < attributeNodes->nodeNr; k++) { + Bool already_exists = 0; + xmlNodePtr attributeNode = attributeNodes->nodeTab[k]; + if (attributeNode->type == XML_ELEMENT_NODE) { + SVGGenAttribute *a = NewSVGGenAttribute(); + a->svg_name = xmlGetProp(attributeNode, "name"); + a->optional = xmlStrEqual(attributeNode->parent->name, "optional"); + svgNameToImplementationName(a->svg_name, a->implementation_name); + getAttributeType(doc, xpathCtx, attributeNode, a); + setAttributeType(a); + for (j=0; jsvg_name, a->svg_name)) { + already_exists = 1; + break; + } + } + if (already_exists) { + deleteSVGGenAttribute(&a); + } else { + //fprintf(stdout, "Adding attribute %s to element %s\n",a->svg_name, e->svg_name); + gf_list_add(attributes, a); + } + } + } +} + +SVGGenAttrGrp *getOneGlobalAttrGrp(xmlDocPtr doc, xmlXPathContextPtr xpathCtx, xmlChar *name) +{ + SVGGenAttrGrp *attgrp = NULL; + xmlNodeSetPtr attrGrpDefNodes; + xmlChar *expr; + u32 j; + int i, l; + + /* attributes group already resolved */ + for (j = 0; j < gf_list_count(globalAttrGrp); j++) { + SVGGenAttrGrp *attgrp = gf_list_get(globalAttrGrp, j); + if (!strcmp(attgrp->name, name)) { + return attgrp; + } + } + + /* new attributes group */ + expr = xmlStrdup("//rng:define[@name=\""); + expr = xmlStrcat(expr, name); + expr = xmlStrcat(expr, "\" and not(rng:empty) and not(rng:notAllowed)]"); + attrGrpDefNodes = findNodes(xpathCtx, expr); + if (!attrGrpDefNodes->nodeNr) { + fprintf(stdout, "Warning: found 0 non-empty or allowed definition for the Group of Attributes: %s\n", name); + return NULL; + } + attgrp = NewSVGGenAttrGrp(); + attgrp->name = gf_strdup(name); + svgNameToImplementationName(attgrp->name, attgrp->imp_name); + gf_list_add(globalAttrGrp, attgrp); + + for (i = 0; i < attrGrpDefNodes->nodeNr; i++) { + xmlNodePtr attrGrp = attrGrpDefNodes->nodeTab[i]; + getRealAttributes(doc, xpathCtx, attrGrp, attgrp->attrs); + + { + xmlNodeSetPtr refNodes; + xpathCtx->node = attrGrp; + refNodes = findNodes(xpathCtx, ".//rng:ref"); + for (l = 0; l < refNodes->nodeNr; l++) { + xmlNodePtr ref = refNodes->nodeTab[l]; + xmlChar *rname = xmlGetProp(ref, "name"); + if (xmlStrstr(rname, ".attr")) { + SVGGenAttrGrp *g2 = getOneGlobalAttrGrp(doc, xpathCtx, rname); + if (g2) { + gf_list_add(attgrp->attrgrps, g2); + } + } + } + } + } + return attgrp; +} + +void getAllGlobalAttrGrp(xmlDocPtr doc, xmlXPathContextPtr xpathCtx) +{ + xmlNodeSetPtr elementNodes = findNodes(xpathCtx, "//rng:define"); + int k; + for (k = 0; k < elementNodes->nodeNr; k++) { + xmlNodePtr elementNode = elementNodes->nodeTab[k]; + if (elementNode->type == XML_ELEMENT_NODE) { + xmlChar *name = NULL; + name = xmlGetProp(elementNode, "name"); + if (xmlStrstr(name, ".attr")) { + getOneGlobalAttrGrp(doc, xpathCtx, name); + } + } + } +} + +GF_List *getElements(xmlDocPtr doc, xmlXPathContextPtr xpathCtx) +{ + xmlChar *expr; + GF_List *elements = gf_list_new(); + xmlNodeSetPtr ATNodes; + xmlNodeSetPtr refNodes, elementNodes = findNodes(xpathCtx, "//rng:element"); + int k, j; + u32 i; + + for (k = 0; k < elementNodes->nodeNr; k++) { + xmlNodePtr elementNode = elementNodes->nodeTab[k]; + if (elementNode->type == XML_ELEMENT_NODE) { + SVGGenElement *e = NewSVGGenElement(); + e->svg_name = xmlStrdup(xmlGetProp(elementNode, "name")); + //fprintf(stdout, "\n\tElement %s\n", e->svg_name); + + svgNameToImplementationName(e->svg_name, e->implementation_name); + + /* getting the */ + expr = xmlStrdup("//rng:define[@name=\""); + if (!xmlStrcmp(e->svg_name, "polygon") || !xmlStrcmp(e->svg_name, "polyline")) { + expr = xmlStrcat(expr, "polyCommon"); + } else { + expr = xmlStrcat(expr, e->svg_name); + } + expr = xmlStrcat(expr, ".AT\"]"); + ATNodes = findNodes(xpathCtx, expr); + if (ATNodes->nodeNr) { + + /* dealing with attributes defined in groups of attributes */ + xpathCtx->node = ATNodes->nodeTab[0]; + refNodes = findNodes(xpathCtx, ".//rng:ref"); + for (j = 0; j nodeNr; j++) { + xmlNodePtr refNode = refNodes->nodeTab[j]; + char *name = xmlGetProp(refNode, "name"); + for (i = 0; i < gf_list_count(globalAttrGrp); i++) { + SVGGenAttrGrp *a = gf_list_get(globalAttrGrp, i); + if (!strcmp(a->name, name)) { + if (isGenericAttributesGroup(a->name)) { + setGenericAttributesFlags(a->name, e); + flattenAttributeGroup(*a, e, 1); + } else { + flattenAttributeGroup(*a, e, 0); + } + break; + } + } + } + + /* dealing with attributes defined directly here */ + getRealAttributes(doc, xpathCtx, ATNodes->nodeTab[0], e->attributes); + } + + /* checking if this element is already present in the list of possible elements + and if not, adding it */ + { + Bool found = 0; + for (i=0; isvg_name, e->svg_name)) { + found = 1; + break; + } + } + if (!found) gf_list_add(elements, e); + } + } + } + return elements; +} + +/*type: 0: header, 1: source*/ +FILE *BeginFile(u32 type) +{ + FILE *f; + + char sPath[GF_MAX_PATH]; + + if (!type) { +#ifdef LOCAL_SVG_NODES + sprintf(sPath, "nodes_svg.h", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); +#else + if (generation_mode == 1) + sprintf(sPath, "..%c..%c..%c..%cinclude%cgpac%cnodes_svg_sa.h", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + else if (generation_mode == 2) + sprintf(sPath, "..%c..%c..%c..%cinclude%cgpac%cnodes_svg_sani.h", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + else if (generation_mode == 3) + sprintf(sPath, "..%c..%c..%c..%cinclude%cgpac%cnodes_svg_da.h", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + +#endif + } else if (type==1) { +#ifdef LOCAL_SVG_NODES + sprintf(sPath, "svg_nodes.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); +#else + if (generation_mode == 1) + sprintf(sPath, "..%c..%c..%c..%csrc%cscenegraph%csvg_nodes_sa.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + else if (generation_mode == 2) + sprintf(sPath, "..%c..%c..%c..%csrc%cscenegraph%csvg_nodes_sani.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + else if (generation_mode == 3) + sprintf(sPath, "..%c..%c..%c..%csrc%cscenegraph%csvg_nodes_da.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); +#endif + } else { +#ifdef LOCAL_SVG_NODES + sprintf(sPath, "lsr_tables.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); +#else + if (generation_mode == 1) + sprintf(sPath, "..%c..%c..%c..%csrc%claser%clsr_tables_sa.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + else if (generation_mode == 2) + sprintf(sPath, "..%c..%c..%c..%csrc%claser%clsr_tables_sani.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + else if (generation_mode == 3) + sprintf(sPath, "..%c..%c..%c..%csrc%claser%clsr_tables.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); + +#endif + } + + f = gf_fopen(sPath, "wt"); + fprintf(f, "%s\n", COPYRIGHT); + + { + time_t rawtime; + time(&rawtime); + fprintf(f, "\n/*\n\tDO NOT MOFIFY - File generated on GMT %s\n\tBY SVGGen for GPAC Version %s\n*/\n\n", asctime(gmtime(&rawtime)), GPAC_VERSION); + } + + if (!type) { + if (generation_mode == 1) { + fprintf(f, "#ifndef _GF_SVG_SA_NODES_H\n"); + fprintf(f, "#define _GF_SVG_SA_NODES_H\n\n"); + } else if (generation_mode == 2) { + fprintf(f, "#ifndef _GF_SVG_SANI_NODES_H\n"); + fprintf(f, "#define _GF_SVG_SANI_NODES_H\n\n"); + } else if (generation_mode == 3) { + fprintf(f, "#ifndef _GF_SVG_NODES_H\n"); + fprintf(f, "#define _GF_SVG_NODES_H\n\n"); + } + fprintf(f, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + } + return f; +} + +void EndFile(FILE *f, u32 type) +{ + if (!type) { + fprintf(f, "#ifdef __cplusplus\n}\n#endif\n\n"); + if (generation_mode == 1) fprintf(f, "\n\n#endif\t\t/*_GF_SVG_SA_NODES_H*/\n\n"); + if (generation_mode == 2) fprintf(f, "\n\n#endif\t\t/*_GF_SVG_SANI_NODES_H*/\n\n"); + if (generation_mode == 3) fprintf(f, "\n\n#endif\t\t/*_GF_SVG_NODES_H*/\n\n"); + } else { + fprintf(f, "\n"); + } + gf_fclose(f); +} + +void generateAttributes(FILE *output, GF_List *attributes, Bool inDefine) +{ + u32 i; + for (i = 0; iimpl_type, att->implementation_name); + else + fprintf(output, "\t%s %s; \\\n", att->impl_type, att->implementation_name); + else + fprintf(output, "\t%s %s;\n", att->impl_type, att->implementation_name); + } +} + +/* +u32 generateAttributesGroupInfo(FILE *output, char * elt_imp_name, SVGGenAttrGrp *attgrp, u32 i) +{ + u32 att_index = i; + u32 k; + for (k=0; kattrgrps); k++) { + SVGGenAttrGrp *ag = gf_list_get(attgrp->attrgrps, k); + att_index = generateAttributesGroupInfo(output, elt_imp_name, ag, att_index); + } + for (k=0; kattrs); k++) { + SVGGenAttribute *at = gf_list_get(attgrp->attrs, k); + generateAttributeInfo(output, elt_imp_name, at, att_index++); + } + return att_index; +} +*/ + +void replaceIncludes(xmlDocPtr doc, xmlXPathContextPtr xpathCtx) +{ + int k; + xmlNodeSetPtr nodes; + xmlXPathObjectPtr xpathObj; + + /* Get all the RNG elements */ + xpathObj = xmlXPathEvalExpression("//rng:include", xpathCtx); + if(xpathObj == NULL || xpathObj->type != XPATH_NODESET) return; + + nodes = xpathObj->nodesetval; + + for (k = 0; k < nodes->nodeNr; k++) { + xmlNodePtr node = nodes->nodeTab[k]; + if (node->type == XML_ELEMENT_NODE) { + xmlChar *href; + xmlDocPtr sub_doc; + + href = xmlGetNoNsProp(node, "href"); + sub_doc = xmlParseFile(href); + xmlReplaceNode(nodes->nodeTab[k], xmlDocGetRootElement(sub_doc)); + } + } + xmlXPathFreeObject(xpathObj); +} + +int main(int argc, char **argv) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr xpathCtx = NULL; + GF_List *svg_elements = NULL; + + xmlInitParser(); + LIBXML_TEST_VERSION + + doc = xmlParseFile(argv[1]); + if (!doc) { + printf("error: could not parse file %s\n", argv[1]); + return -1; + } + + xpathCtx = xmlXPathNewContext(doc); + if(xpathCtx == NULL) { + fprintf(stderr,"Error: unable to create new XPath context\n"); + xmlFreeDoc(doc); + return(-1); + } + xmlXPathRegisterNs(xpathCtx, RNG_PREFIX, RNG_NS); + xmlXPathRegisterNs(xpathCtx, RNGA_PREFIX, RNGA_NS); + xmlXPathRegisterNs(xpathCtx, SVGA_PREFIX, SVGA_NS); + + replaceIncludes(doc, xpathCtx); + xmlSaveFile("completerng_props.xml", doc); + + globalAttrGrp = gf_list_new(); + getAllGlobalAttrGrp(doc, xpathCtx); + + svg_elements = getElements(doc, xpathCtx); + svg_elements = sortElements(svg_elements); + + if (argv[2] && !strcmp(argv[2], "-html")) { + generate_table(svg_elements); + } else { + if (generation_mode == 1) generateSVGCode_V1(svg_elements); + if (generation_mode == 2) generateSVGCode_V2(svg_elements); + if (generation_mode == 3) generateSVGCode_V3(svg_elements); + } + + xmlXPathFreeContext(xpathCtx); + //xmlFreeDoc(doc); + + xmlCleanupParser(); + return 0; +} + + diff --git a/applications/generators/SVG/svggen.h b/applications/generators/SVG/svggen.h new file mode 100644 index 0000000..a2c97e3 --- /dev/null +++ b/applications/generators/SVG/svggen.h @@ -0,0 +1,195 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / SVG Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _SVGGEN_H_ +#define _SVGGEN_H_ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* if defined generates .c/.h directly in the appropriate GPAC source folders */ +#undef LOCAL_SVG_NODES + +/* + Modes for generating SVG code + - 1 means static allocation of attributes (including properties, use Tiny-1.2-NG) + - 2 means static allocation of attributes (only useful properties on nodes, use Tiny-1.2-NG-noproperties) + - 3 means dynamic allocation of attributes (including properties) +*/ +static u32 generation_mode = 3; + +#define RNG_NS "http://relaxng.org/ns/structure/1.0" +#define RNGA_NS "http://relaxng.org/ns/compatibility/annotations/1.0" +#define SVGA_NS "http://www.w3.org/2005/02/svg-annotations" + +#define RNG_PREFIX "rng" +#define RNGA_PREFIX "rnga" +#define SVGA_PREFIX "svg" + +#define COPYRIGHT "/*\n * GPAC - Multimedia Framework C SDK\n *\n * Authors: Cyril Concolato - Jean Le Feuvre\n * Copyright (c) Telecom ParisTech 2000-2012 - All rights reserved\n *\n * This file is part of GPAC / SVG Scene Graph sub-project\n *\n * GPAC is free software; you can redistribute it and/or modify\n * it under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2, or (at your option)\n * any later version.\n *\n * GPAC is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details. \n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; see the file COPYING. If not, write to\n * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n" + + +/* + type declarations +*/ + +typedef struct +{ + xmlChar *svg_name; + char implementation_name[50]; + + Bool has_svg_generic; + Bool has_xml_generic; + Bool has_media_properties; + Bool has_properties; + Bool has_opacity_properties; + Bool has_focus; + Bool has_xlink; + Bool has_timing; + Bool has_sync; + Bool has_animation; + Bool has_conditional; + Bool has_transform; + Bool has_xy; + + GF_List *attributes; + GF_List *generic_attributes; + + u32 nb_atts; +} SVGGenElement; + +typedef struct { + xmlChar *svg_name; + char implementation_name[50]; + xmlChar *svg_type; + char impl_type[50]; + u8 animatable; + u8 inheritable; + Bool optional; + xmlChar *default_value; + u32 index; +} SVGGenAttribute; +SVGGenAttribute *NewSVGGenAttribute(); + +typedef struct { + char *name; + char imp_name[50]; + GF_List *attrs; + GF_List *attrgrps; +} SVGGenAttrGrp; + + + +/******************************************* + * Structures needed for static allocation * + *******************************************/ + +static GF_List *globalAttrGrp; + +/* SVG Generic */ +static char *core[] = { "id", "class", "xml:id", "xml:base", "xml:lang", "xml:space", "externalResourceRequired" }; + +/* Media Properties */ +static char *media_properties[] = { + "audio-level", "display", "image-rendering", "pointer-events", "shape-rendering", "text-rendering", + "viewport-fill", "viewport-fill-opacity", "visibility" +}; + +/* others */ +static char *other_properties[] = { + "color", "color-rendering", "display-align", "fill", "fill-opacity", "fill-rule", + "font-family", "font-size", "font-style", "font-weight", "line-increment", + "solid-color", "solid-opacity", "stop-color", "stop-opacity", + "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", + "stroke-opacity", "stroke-width", "text-align", "text-anchor", "vector-effect" +}; + +/* only opacity on image */ +static char *opacity_properties[] = { + "opacity" +}; + +/* Focus */ +static char *focus[] = { + "focusHighlight", "focusable", "nav-down", "nav-down-left", "nav-down-right", + "nav-left", "nav-next", "nav-prev", "nav-right", "nav-up", "nav-up-left", "nav-up-right" +}; + +/* Xlink */ +static char *xlink[] = { + "xlink:href", "xlink:show", "xlink:title", "xlink:actuate", "xlink:role", "xlink:arcrole", "xlink:type" +}; + +/* Timing */ +static char *timing[] = { + "begin", "end", "dur", "repeatCount", "repeatDur", "restart", "min", "max", "fill", "clipBegin", "clipEnd" +}; + +/* Sync */ +static char *sync[] = { + "syncBehavior", "syncBehaviorDefault", "syncTolerance", "syncToleranceDefault", "syncMaster", "syncReference" +}; + +/* Animation */ +static char *anim[] = { + "attributeName", "attributeType", "to", "from", "by", "values", + "type", "calcMode", "keySplines", "keyTimes", "accumulate", "additive", "lsr:enabled" +}; + +/* Conditional Processing */ +static char *conditional[] = { + "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "systemLanguage" +}; + +typedef struct { + int array_length; + char **array; // mapping of constructs to the RNG definition +} _atts; + +static _atts generic_attributes[] = { + { 7, core }, + { 26, other_properties }, + { 9, media_properties }, + { 1, opacity_properties }, + { 12, focus }, + { 7, xlink }, + { 11, timing }, + { 6, sync }, + { 13, anim }, + { 5, conditional} +}; + +FILE *BeginFile(u32 type); +void EndFile(FILE *f, u32 type); + + +#endif // _SVGGEN_H_ diff --git a/applications/generators/SVG/v1.c b/applications/generators/SVG/v1.c new file mode 100644 index 0000000..a48bbbd --- /dev/null +++ b/applications/generators/SVG/v1.c @@ -0,0 +1,608 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / SVG Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "svggen.h" + +void generateNode(FILE *output, SVGGenElement* svg_elt) +{ + fprintf(output, "typedef struct _tagSVG_SA_%sElement\n{\n", svg_elt->implementation_name); + + if (svg_elt->has_transform) { + fprintf(output, "\tTRANSFORMABLE_SVG_ELEMENT\n"); + } else { + fprintf(output, "\tBASE_SVG_ELEMENT\n"); + } + + if (!strcmp(svg_elt->implementation_name, "conditional")) { + fprintf(output, "\tSVGCommandBuffer updates;\n"); + } + + generateAttributes(output, svg_elt->attributes, 0); + + /*special case for handler node*/ + if (!strcmp(svg_elt->implementation_name, "handler")) { + fprintf(output, "\tvoid (*handle_event)(GF_Node *hdl, GF_DOM_Event *event);\n"); + } + fprintf(output, "} SVG_SA_%sElement;\n\n\n", svg_elt->implementation_name); +} + + +void generateAttributeInfo(FILE *output, char * elt_imp_name, SVGGenAttribute *att, u32 i) +{ + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"%s\";\n", att->svg_name); + fprintf(output, "\t\t\tinfo->fieldType = %s_datatype;\n", att->impl_type); + fprintf(output, "\t\t\tinfo->far_ptr = & ((SVG_SA_%sElement *)node)->%s;\n", elt_imp_name, att->implementation_name); + fprintf(output, "\t\t\treturn GF_OK;\n"); +} + +u32 generateCoreInfo(FILE *output, SVGGenElement *elt, u32 start) +{ + u32 i = start; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"id\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_ID_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = gf_node_get_name_address(node);\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"xml:id\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_ID_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = gf_node_get_name_address(node);\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"class\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_String_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SA_Element *)node)->core->_class;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"xml:lang\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_LanguageID_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SA_Element *)node)->core->lang;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"xml:base\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_String_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SA_Element *)node)->core->base;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"xml:space\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = XML_Space_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SA_Element *)node)->core->space;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"externalResourcesRequired\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Boolean_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SA_Element *)node)->core->eRR;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + return i; +} + +void generateAttributeInfoFlat(FILE *output, char *pointer, char *name, char *type, u32 i) +{ + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"%s\";\n", name); + fprintf(output, "\t\t\tinfo->fieldType = %s_datatype;\n", type); + fprintf(output, "\t\t\tinfo->far_ptr = &%s;\n", pointer); + fprintf(output, "\t\t\treturn GF_OK;\n"); +} + +u32 generateTransformInfo(FILE *output, SVGGenElement *elt, u32 start) +{ + u32 i = start; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"transform\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Transform_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVGTransformableElement *)node)->transform;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + return i; +} + +u32 generateMotionTransformInfo(FILE *output, SVGGenElement *elt, u32 start) +{ + u32 i = start; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"motionTransform\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Motion_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = ((SVGTransformableElement *)node)->motionTransform;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + return i; +} + +u32 generateXYInfo(FILE *output, SVGGenElement *elt, u32 start) +{ + u32 i = start; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"x\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Coordinate_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVGTransformableElement *)node)->xy.x;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"y\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Coordinate_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVGTransformableElement *)node)->xy.y;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + return i; +} + +u32 generateGenericInfo(FILE *output, SVGGenElement *elt, u32 index, char *pointer_root, u32 start) +{ + u32 i = start; + int k; + for (k=0; k < generic_attributes[index].array_length; k++) { + char *att_name = generic_attributes[index].array[k]; + SVGGenAttribute *a = findAttribute(elt, att_name); + if (a) { + char pointer[500]; + if (strstr(att_name, "xlink:")) { + sprintf(pointer, "%s%s", pointer_root, att_name+6); + } else if (strstr(att_name, "xml:")) { + sprintf(pointer, "%s%s", pointer_root, att_name+4); + } else { + char imp_name[50]; + svgNameToImplementationName(att_name, imp_name); + sprintf(pointer, "%s%s", pointer_root, imp_name); + } + generateAttributeInfoFlat(output, pointer, a->svg_name, a->impl_type, i); + i++; + } + } + return i; +} + +u32 generateIndexInfo(FILE *output, SVGGenElement *elt, u32 index, u32 start) +{ + u32 i = start; + int k; + for (k=0; k < generic_attributes[index].array_length; k++) { + char *att_name = generic_attributes[index].array[k]; + SVGGenAttribute *a = findAttribute(elt, att_name); + if (a) { + fprintf(output, "\tif(!strcmp(\"%s\", name)) return %d;\n", att_name, i); + i++; + } + } + return i; +} + +void generateNodeImpl(FILE *output, SVGGenElement* svg_elt) +{ + u32 i; + + /***************************************************/ + /* Constructor */ + /***************************************************/ + fprintf(output, "void *gf_svg_new_%s()\n{\n\tSVG_SA_%sElement *p;\n", svg_elt->implementation_name,svg_elt->implementation_name); + fprintf(output, "\tGF_SAFEALLOC(p, SVG_SA_%sElement);\n\tif (!p) return NULL;\n\tgf_node_setup((GF_Node *)p, TAG_SVG_%s);\n\tgf_sg_parent_setup((GF_Node *) p);\n",svg_elt->implementation_name,svg_elt->implementation_name); + + fprintf(output, "\tgf_svg_sa_init_core((SVG_SA_Element *)p);\n"); + if (svg_elt->has_properties || + svg_elt->has_media_properties || + svg_elt->has_opacity_properties) { + fprintf(output, "\tgf_svg_sa_init_properties((SVG_SA_Element *)p);\n"); + } + if (svg_elt->has_focus) { + fprintf(output, "\tgf_svg_sa_init_focus((SVG_SA_Element *)p);\n"); + } + if (svg_elt->has_xlink) { + fprintf(output, "\tgf_svg_sa_init_xlink((SVG_SA_Element *)p);\n"); + } + if (svg_elt->has_timing) { + fprintf(output, "\tgf_svg_sa_init_timing((SVG_SA_Element *)p);\n"); + } + if (svg_elt->has_sync) { + fprintf(output, "\tgf_svg_sa_init_sync((SVG_SA_Element *)p);\n"); + } + if (svg_elt->has_animation) { + fprintf(output, "\tgf_svg_sa_init_anim((SVG_SA_Element *)p);\n"); + } + if (svg_elt->has_conditional) { + fprintf(output, "\tgf_svg_sa_init_conditional((SVG_SA_Element *)p);\n"); + } + + if (svg_elt->has_transform) { + fprintf(output, "\tgf_mx2d_init(p->transform.mat);\n"); + } + + if (!strcmp(svg_elt->implementation_name, "conditional")) { + fprintf(output, "\tgf_svg_sa_init_lsr_conditional(&p->updates);\n"); + fprintf(output, "\tgf_svg_sa_init_timing((SVG_SA_Element *)p);\n"); + + } + + for (i = 0; i < gf_list_count(svg_elt->attributes); i++) { + SVGGenAttribute *att = gf_list_get(svg_elt->attributes, i); + /* Initialization of complex types */ + if ( !strcmp("SVG_Points", att->impl_type) || + !strcmp("SVG_Coordinates", att->impl_type) || + !strcmp("SMIL_KeyPoints", att->impl_type)) { + fprintf(output, "\tp->%s = gf_list_new();\n", att->implementation_name); + } else if (!strcmp("SVG_PathData", att->impl_type) && !strcmp(svg_elt->svg_name, "animateMotion")) { + fprintf(output, "#ifdef USE_GF_PATH\n"); + fprintf(output, "\tgf_path_reset(&p->path);\n"); + fprintf(output, "#else\n"); + fprintf(output, "\tp->path.commands = gf_list_new();\n"); + fprintf(output, "\tp->path.points = gf_list_new();\n"); + fprintf(output, "#endif\n"); + } else if (!strcmp("SVG_PathData", att->impl_type)) { + fprintf(output, "#ifdef USE_GF_PATH\n"); + fprintf(output, "\tgf_path_reset(&p->d);\n"); + fprintf(output, "#else\n"); + fprintf(output, "\tp->d.commands = gf_list_new();\n"); + fprintf(output, "\tp->d.points = gf_list_new();\n"); + fprintf(output, "#endif\n"); + } else if (!strcmp(att->svg_name, "lsr:enabled")) { + fprintf(output, "\tp->lsr_enabled = 1;\n"); + } + } + /*some default values*/ + if (!strcmp(svg_elt->svg_name, "svg")) { + fprintf(output, "\tp->width.type = SVG_NUMBER_PERCENTAGE;\n"); + fprintf(output, "\tp->width.value = INT2FIX(100);\n"); + fprintf(output, "\tp->height.type = SVG_NUMBER_PERCENTAGE;\n"); + fprintf(output, "\tp->height.value = INT2FIX(100);\n"); + } + else if (!strcmp(svg_elt->svg_name, "solidColor")) { + fprintf(output, "\tp->properties->solid_opacity.value = FIX_ONE;\n"); + } + else if (!strcmp(svg_elt->svg_name, "stop")) { + fprintf(output, "\tp->properties->stop_opacity.value = FIX_ONE;\n"); + } + else if (!strcmp(svg_elt->svg_name, "linearGradient")) { + fprintf(output, "\tp->x2.value = FIX_ONE;\n"); + fprintf(output, "\tgf_mx2d_init(p->gradientTransform.mat);\n"); + } + else if (!strcmp(svg_elt->svg_name, "radialGradient")) { + fprintf(output, "\tp->cx.value = FIX_ONE/2;\n"); + fprintf(output, "\tp->cy.value = FIX_ONE/2;\n"); + fprintf(output, "\tp->r.value = FIX_ONE/2;\n"); + fprintf(output, "\tgf_mx2d_init(p->gradientTransform.mat);\n"); + fprintf(output, "\tp->fx.value = FIX_ONE/2;\n"); + fprintf(output, "\tp->fy.value = FIX_ONE/2;\n"); + } + else if (!strcmp(svg_elt->svg_name, "video") || !strcmp(svg_elt->svg_name, "audio") || !strcmp(svg_elt->svg_name, "animation")) { + fprintf(output, "\tp->timing->dur.type = SMIL_DURATION_MEDIA;\n"); + } + fprintf(output, "\treturn p;\n}\n\n"); + + /***************************************************/ + /* Destructor */ + /***************************************************/ + fprintf(output, "static void gf_svg_sa_%s_del(GF_Node *node)\n{\n", svg_elt->implementation_name); + fprintf(output, "\tSVG_SA_%sElement *p = (SVG_SA_%sElement *)node;\n", svg_elt->implementation_name, svg_elt->implementation_name); + + fprintf(output, "\tgf_svg_sa_reset_base_element((SVG_SA_Element *)p);\n"); + + if (!strcmp(svg_elt->implementation_name, "conditional")) { + fprintf(output, "\tgf_svg_sa_reset_lsr_conditional(&p->updates);\n"); + } + else if (!strcmp(svg_elt->implementation_name, "a")) { + fprintf(output, "\tif (p->target) free(p->target);\n"); + } + + for (i = 0; i < gf_list_count(svg_elt->attributes); i++) { + SVGGenAttribute *att = gf_list_get(svg_elt->attributes, i); + if (!strcmp("SMIL_KeyPoints", att->impl_type)) { + fprintf(output, "\tgf_smil_delete_key_types(p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_Coordinates", att->impl_type)) { + fprintf(output, "\tgf_svg_delete_coordinates(p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_Points", att->impl_type)) { + fprintf(output, "\tgf_svg_delete_points(p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_PathData", att->impl_type)) { + if (!strcmp(svg_elt->svg_name, "animateMotion")) { + fprintf(output, "\tgf_svg_reset_path(p->path);\n"); + } else { + fprintf(output, "\tgf_svg_reset_path(p->d);\n"); + } + } else if (!strcmp("XMLRI", att->impl_type)) { + fprintf(output, "\tgf_svg_reset_iri(node->sgprivate->scenegraph, &p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_FontFamily", att->impl_type)) { + fprintf(output, "\tif (p->%s.value) free(p->%s.value);\n", att->implementation_name, att->implementation_name); + } else if (!strcmp("SVG_String", att->impl_type) || !strcmp("SVG_ContentType", att->impl_type)) { + fprintf(output, "\tfree(p->%s);\n", att->implementation_name); + } + } + if (svg_elt->has_transform) { + fprintf(output, "\tif (p->motionTransform) free(p->motionTransform);\n"); + } + + fprintf(output, "\tgf_sg_parent_reset((GF_Node *) p);\n"); + fprintf(output, "\tgf_node_free((GF_Node *)p);\n"); + fprintf(output, "}\n\n"); + + /***************************************************/ + /* Attribute Access */ + /***************************************************/ + fprintf(output, "static GF_Err gf_svg_sa_%s_get_attribute(GF_Node *node, GF_FieldInfo *info)\n{\n", svg_elt->implementation_name); + fprintf(output, "\tswitch (info->fieldIndex) {\n"); + svg_elt->nb_atts = 0; + svg_elt->nb_atts = generateCoreInfo(output, svg_elt, svg_elt->nb_atts); + + if (svg_elt->has_media_properties) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 2, "((SVG_SA_Element *)node)->properties->", svg_elt->nb_atts); + if (svg_elt->has_properties) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 1, "((SVG_SA_Element *)node)->properties->", svg_elt->nb_atts); + if (svg_elt->has_opacity_properties) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 3, "((SVG_SA_Element *)node)->properties->", svg_elt->nb_atts); + if (svg_elt->has_focus) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 4, "((SVG_SA_Element *)node)->focus->", svg_elt->nb_atts); + if (svg_elt->has_xlink) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 5, "((SVG_SA_Element *)node)->xlink->", svg_elt->nb_atts); + if (svg_elt->has_timing) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 6, "((SVG_SA_Element *)node)->timing->", svg_elt->nb_atts); + if (svg_elt->has_sync) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 7, "((SVG_SA_Element *)node)->sync->", svg_elt->nb_atts); + if (svg_elt->has_animation) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 8, "((SVG_SA_Element *)node)->anim->", svg_elt->nb_atts); + if (svg_elt->has_conditional) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 9, "((SVG_SA_Element *)node)->conditional->", svg_elt->nb_atts); + if (svg_elt->has_transform) { + svg_elt->nb_atts = generateTransformInfo(output, svg_elt, svg_elt->nb_atts); + svg_elt->nb_atts = generateMotionTransformInfo(output, svg_elt, svg_elt->nb_atts); + } + if (svg_elt->has_xy) + svg_elt->nb_atts = generateXYInfo(output, svg_elt, svg_elt->nb_atts); + + for (i = 0; i < gf_list_count(svg_elt->attributes); i++) { + SVGGenAttribute *att = gf_list_get(svg_elt->attributes, i); + generateAttributeInfo(output, svg_elt->implementation_name, att, svg_elt->nb_atts++); + } + fprintf(output, "\t\tdefault: return GF_BAD_PARAM;\n\t}\n}\n\n"); + + /***************************************************/ + /* gf_svg_sa_%s_get_attribute_index_from_name */ + /***************************************************/ + fprintf(output, "s32 gf_svg_sa_%s_get_attribute_index_from_name(char *name)\n{\n", svg_elt->implementation_name); + { + u32 att_index = 0; + fprintf(output, "\tif(!strcmp(\"id\", name)) return %d;\n", att_index); + att_index++; + fprintf(output, "\tif(!strcmp(\"xml:id\", name)) return %d;\n", att_index); + att_index++; + fprintf(output, "\tif(!strcmp(\"class\", name)) return %d;\n", att_index); + att_index++; + fprintf(output, "\tif(!strcmp(\"xml:lang\", name)) return %d;\n", att_index); + att_index++; + fprintf(output, "\tif(!strcmp(\"xml:base\", name)) return %d;\n", att_index); + att_index++; + fprintf(output, "\tif(!strcmp(\"xml:space\", name)) return %d;\n", att_index); + att_index++; + fprintf(output, "\tif(!strcmp(\"externalResourcesRequired\", name)) return %d;\n", att_index); + att_index++; + if (svg_elt->has_media_properties) + att_index = generateIndexInfo(output, svg_elt, 2, att_index); + if (svg_elt->has_properties) + att_index = generateIndexInfo(output, svg_elt, 1, att_index); + if (svg_elt->has_opacity_properties) + att_index = generateIndexInfo(output, svg_elt, 3, att_index); + if (svg_elt->has_focus) + att_index = generateIndexInfo(output, svg_elt, 4, att_index); + if (svg_elt->has_xlink) + att_index = generateIndexInfo(output, svg_elt, 5, att_index); + if (svg_elt->has_timing) + att_index = generateIndexInfo(output, svg_elt, 6, att_index); + if (svg_elt->has_sync) + att_index = generateIndexInfo(output, svg_elt, 7, att_index); + if (svg_elt->has_animation) + att_index = generateIndexInfo(output, svg_elt, 8, att_index); + if (svg_elt->has_conditional) + att_index = generateIndexInfo(output, svg_elt, 9, att_index); + if (svg_elt->has_transform) { + fprintf(output, "\tif(!strcmp(\"transform\", name)) return %d;\n", att_index); + att_index++; + /*motionTransform*/ + fprintf(output, "\tif(!strcmp(\"motionTransform\", name)) return %d;\n", att_index); + att_index++; + } + if (svg_elt->has_xy) { + fprintf(output, "\tif(!strcmp(\"x\", name)) return %d;\n", att_index); + att_index++; + fprintf(output, "\tif(!strcmp(\"y\", name)) return %d;\n", att_index); + att_index++; + } + + for (i = 0; i < gf_list_count(svg_elt->attributes); i++) { + SVGGenAttribute *att = gf_list_get(svg_elt->attributes, i); + fprintf(output, "\tif(!strcmp(\"%s\", name)) return %d;\n", att->svg_name, att_index); + att_index++; + } + } + fprintf(output, "\treturn -1;\n}\n\n"); +} + +void generateSVGCode_V1(GF_List *svg_elements) +{ + FILE *output; + u32 i; + + /***************************************************/ + /***************************************************/ + /*************** Creating .h file ******************/ + /***************************************************/ + /***************************************************/ + output = BeginFile(0); + fprintf(output, "#include \n\n\n"); + fprintf(output, "/* Definition of SVG element internal tags */\n"); + fprintf(output, "/* TAG names are made of \"TAG_SVG\" + SVG element name (with - replaced by _) */\n"); + + /* write all tags */ + fprintf(output, "enum {\n"); + for (i=0; iimplementation_name); + } else { + fprintf(output, ",\n\tTAG_SVG_%s", elt->implementation_name); + } + } + + fprintf(output, ",\n\t/*undefined elements (when parsing) use this tag*/\n\tTAG_SVG_UndefinedElement\n};\n\n"); + + fprintf(output, "/******************************************\n"); + fprintf(output, "* SVG Elements structure definitions *\n"); + fprintf(output, "*******************************************/\n"); + for (i=0; i\n\n"); + + fprintf(output, "#ifndef GPAC_DISABLE_SVG\n\n"); + fprintf(output, "#include \n\n"); + fprintf(output, "#ifdef GPAC_ENABLE_SVG_SA\n\n"); + for (i=0; iimplementation_name,elt->implementation_name); + } + fprintf(output, "\t\tdefault: return NULL;\n\t}\n}\n\n"); + + /***************************************************/ + /* void gf_svg_sa_element_del(SVG_SA_Element *elt) */ + /***************************************************/ + fprintf(output, "void gf_svg_sa_element_del(SVG_SA_Element *elt)\n{\n"); + fprintf(output, "\tGF_Node *node = (GF_Node *)elt;\n"); + fprintf(output, "\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iimplementation_name, elt->implementation_name); + } + fprintf(output, "\t\tdefault: return;\n\t}\n}\n\n"); + + /***************************************************/ + /* u32 gf_svg_sa_get_attribute_count(SVG_SA_Element *elt) */ + /***************************************************/ + fprintf(output, "u32 gf_svg_sa_get_attribute_count(GF_Node *node)\n{\n"); + fprintf(output, "\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iimplementation_name, elt->nb_atts); + } + fprintf(output, "\t\tdefault: return 0;\n\t}\n}\n\n"); + + /***********************************************************************/ + /* GF_Err gf_svg_sa_get_attribute_info(GF_Node *node, GF_FieldInfo *info) */ + /***********************************************************************/ + fprintf(output, "GF_Err gf_svg_sa_get_attribute_info(GF_Node *node, GF_FieldInfo *info)\n{\n"); + fprintf(output, "\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iimplementation_name, elt->implementation_name); + } + fprintf(output, "\t\tdefault: return GF_BAD_PARAM;\n\t}\n}\n\n"); + + /****************************************************************/ + /* u32 gf_svg_sa_node_type_by_class_name(const char *element_name) */ + /****************************************************************/ + fprintf(output, "u32 gf_svg_sa_node_type_by_class_name(const char *element_name)\n{\n\tif (!element_name) return TAG_UndefinedNode;\n"); + for (i=0; isvg_name, elt->implementation_name); + } + fprintf(output, "\treturn TAG_UndefinedNode;\n}\n\n"); + + + /***************************************************/ + /* const char *gf_svg_sa_get_element_name(u32 tag) */ + /***************************************************/ + fprintf(output, "const char *gf_svg_sa_get_element_name(u32 tag)\n{\n\tswitch(tag) {\n"); + for (i=0; iimplementation_name, elt->svg_name); + } + fprintf(output, "\tdefault: return \"UndefinedNode\";\n\t}\n}\n\n"); + + /***************************************************/ + /* const char *gf_svg_sa_get_attribute_index_by_name(u32 tag) */ + /***************************************************/ + fprintf(output, "s32 gf_svg_sa_get_attribute_index_by_name(GF_Node *node, char *name)\n{\n\tswitch(node->sgprivate->tag) {\n"); + for (i=0; iimplementation_name, elt->implementation_name); + } + fprintf(output, "\tdefault: return -1;\n\t}\n}\n\n"); + + /***************************************************/ + /* Bool gf_svg_is_element_transformable(u32 tag) */ + /***************************************************/ + fprintf(output, "Bool gf_svg_is_element_transformable(u32 tag)\n{\n\tswitch(tag) {\n"); + for (i=0; iimplementation_name); + if (elt->has_transform) fprintf(output, "return 1;\n"); + else fprintf(output, "return 0;\n"); + } + fprintf(output, "\tdefault: return 0;\n\t}\n}\n"); + + fprintf(output, "#endif /*GPAC_ENABLE_SVG_SA*/\n"); + fprintf(output, "#endif /*GPAC_DISABLE_SVG*/\n\n"); + EndFile(output, 1); + + generate_laser_tables(svg_elements); +} + diff --git a/applications/generators/SVG/v2.c b/applications/generators/SVG/v2.c new file mode 100644 index 0000000..f0359aa --- /dev/null +++ b/applications/generators/SVG/v2.c @@ -0,0 +1,463 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / SVG Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "svggen.h" + +void generateAttributes2(FILE *output, GF_List *attributes) +{ + u32 i; + for (i = 0; iimplementation_name, "transform")) continue; + fprintf(output, "\t%s %s;\n", att->impl_type, att->implementation_name); + } +} + +void generateNode2(FILE *output, SVGGenElement* svg_elt) +{ + fprintf(output, "typedef struct _tagSVG_SANI_%sElement\n{\n", svg_elt->implementation_name); + + if (svg_elt->has_transform) { + fprintf(output, "\tTRANSFORMABLE_SVG_SANI_ELEMENT\n"); + } else { + fprintf(output, "\tBASE_SVG_SANI_ELEMENT\n"); + } + + if (!strcmp(svg_elt->implementation_name, "conditional")) { + fprintf(output, "\tSVGCommandBuffer updates;\n"); + } + + generateAttributes2(output, svg_elt->attributes); + + /*special case for handler node*/ + if (!strcmp(svg_elt->implementation_name, "handler")) { + fprintf(output, "\tvoid (*handle_event)(GF_Node *hdl, GF_DOM_Event *event);\n"); + } + fprintf(output, "} SVG_SANI_%sElement;\n\n\n", svg_elt->implementation_name); +} + +void generateAttributeInfo2(FILE *output, char * elt_imp_name, SVGGenAttribute *att, u32 i) +{ + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"%s\";\n", att->svg_name); + fprintf(output, "\t\t\tinfo->fieldType = %s_datatype;\n", att->impl_type); + fprintf(output, "\t\t\tinfo->far_ptr = & ((SVG_SANI_%sElement *)node)->%s;\n", elt_imp_name, att->implementation_name); + fprintf(output, "\t\t\treturn GF_OK;\n"); +} + +u32 generateTransformInfo2(FILE *output, SVGGenElement *elt, u32 start) +{ + u32 i = start; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"transform\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Transform_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SANI_TransformableElement *)node)->transform;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + return i; +} + +u32 generateMotionTransformInfo2(FILE *output, SVGGenElement *elt, u32 start) +{ + u32 i = start; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"motionTransform\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Transform_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = ((SVG_SANI_TransformableElement *)node)->motionTransform;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + return i; +} + +u32 generateXYInfo2(FILE *output, SVGGenElement *elt, u32 start) +{ + u32 i = start; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"x\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Coordinate_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SANI_TransformableElement *)node)->xy.x;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + + fprintf(output, "\t\tcase %d:\n", i); + fprintf(output, "\t\t\tinfo->name = \"y\";\n"); + fprintf(output, "\t\t\tinfo->fieldType = SVG_Coordinate_datatype;\n"); + fprintf(output, "\t\t\tinfo->far_ptr = &((SVG_SANI_TransformableElement *)node)->xy.y;\n"); + fprintf(output, "\t\t\treturn GF_OK;\n"); + i++; + return i; +} + +void generateNodeImpl2(FILE *output, SVGGenElement* svg_elt) +{ + u32 i; + + /* Constructor */ + fprintf(output, "void *gf_svg_sani_new_%s()\n{\n\tSVG_SANI_%sElement *p;\n", svg_elt->implementation_name,svg_elt->implementation_name); + fprintf(output, "\tGF_SAFEALLOC(p, SVG_SANI_%sElement);\n\tif (!p) return NULL;\n\tgf_node_setup((GF_Node *)p, TAG_SVG_SANI_%s);\n\tgf_sg_parent_setup((GF_Node *) p);\n",svg_elt->implementation_name,svg_elt->implementation_name); + + fprintf(output, "\tgf_svg_sani_init_core((SVG_SANI_Element *)p);\n"); + if (svg_elt->has_focus) { + fprintf(output, "\tgf_svg_sani_init_focus((SVG_SANI_Element *)p);\n"); + } + if (svg_elt->has_xlink) { + fprintf(output, "\tgf_svg_sani_init_xlink((SVG_SANI_Element *)p);\n"); + } + if (svg_elt->has_timing) { + fprintf(output, "\tgf_svg_sani_init_timing((SVG_SANI_Element *)p);\n"); + } + if (svg_elt->has_sync) { + fprintf(output, "\tgf_svg_sani_init_sync((SVG_SANI_Element *)p);\n"); + } + if (svg_elt->has_animation) { + fprintf(output, "\tgf_svg_sani_init_anim((SVG_SANI_Element *)p);\n"); + } + if (svg_elt->has_conditional) { + fprintf(output, "\tgf_svg_sani_init_conditional((SVG_SANI_Element *)p);\n"); + } + + if (svg_elt->has_transform) { + fprintf(output, "\tgf_mx2d_init(p->transform.mat);\n"); + } + + if (!strcmp(svg_elt->implementation_name, "conditional")) { + fprintf(output, "\tgf_svg_sa_init_lsr_conditional(&p->updates);\n"); + fprintf(output, "\tgf_svg_sani_init_timing((SVG_SANI_Element *)p);\n"); + + } + + for (i = 0; i < gf_list_count(svg_elt->attributes); i++) { + SVGGenAttribute *att = gf_list_get(svg_elt->attributes, i); + + /* forcing initialization of old-properties */ + if (!strcmp("audio-level", att->svg_name)) { + fprintf(output, "\tp->audio_level.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->audio_level.value = FIX_ONE;\n"); + } else if (!strcmp("display", att->svg_name)) { + fprintf(output, "\tp->display = SVG_DISPLAY_INLINE;\n"); + } else if (!strcmp("display-align", att->svg_name)) { + fprintf(output, "\tp->display_align = SVG_DISPLAYALIGN_AUTO;\n"); + } else if (!strcmp("fill", att->svg_name)) { + fprintf(output, "\tp->fill.type = SVG_PAINT_COLOR;\n"); + fprintf(output, "\tp->fill.color.type = SVG_COLOR_RGBCOLOR;\n"); + } else if (!strcmp("fill-opacity", att->svg_name)) { + fprintf(output, "\tp->fill_opacity.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->fill_opacity.value = FIX_ONE;\n"); + } else if (!strcmp("fill-rule", att->svg_name)) { + fprintf(output, "\tp->fill_rule = SVG_FILLRULE_NONZERO;\n"); + } else if (!strcmp("font-family", att->svg_name)) { + fprintf(output, "\tp->font_family.type = SVG_FONTFAMILY_VALUE;\n"); + fprintf(output, "\tp->font_family.value = strdup(\"Arial\");\n"); + } else if (!strcmp("font-size", att->svg_name)) { + fprintf(output, "\tp->font_size.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->font_size.value = 12*FIX_ONE;\n"); + } else if (!strcmp("font-style", att->svg_name)) { + fprintf(output, "\tp->font_style = SVG_FONTSTYLE_NORMAL;\n"); + } else if (!strcmp("font-variant", att->svg_name)) { + fprintf(output, "\tp->font_variant = SVG_FONTVARIANT_NORMAL;\n"); + } else if (!strcmp("font-weight", att->svg_name)) { + fprintf(output, "\tp->font_weight = SVG_FONTWEIGHT_NORMAL;\n"); + } else if (!strcmp("line-increment", att->svg_name)) { + fprintf(output, "\tp->line_increment.type = SVG_NUMBER_AUTO;\n"); + fprintf(output, "\tp->line_increment.value = FIX_ONE;\n"); + } else if (!strcmp("opacity", att->svg_name)) { + fprintf(output, "\tp->opacity.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->opacity.value = FIX_ONE;\n"); + } else if (!strcmp("solid-color", att->svg_name)) { + fprintf(output, "\tp->solid_color.type = SVG_PAINT_COLOR;\n"); + fprintf(output, "\tp->solid_color.color.type = SVG_COLOR_RGBCOLOR;\n"); + } else if (!strcmp("solid-opacity", att->svg_name)) { + fprintf(output, "\tp->solid_opacity.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->solid_opacity.value = FIX_ONE;\n"); + } else if (!strcmp("solid-color", att->svg_name)) { + fprintf(output, "\tp->stop_color.type = SVG_PAINT_COLOR;\n"); + fprintf(output, "\tp->stop_color.color.type = SVG_COLOR_RGBCOLOR;\n"); + } else if (!strcmp("stop-opacity", att->svg_name)) { + fprintf(output, "\tp->stop_opacity.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->stop_opacity.value = FIX_ONE;\n"); + } else if (!strcmp("stroke", att->svg_name)) { + fprintf(output, "\tp->stroke.type = SVG_PAINT_NONE;\n"); + fprintf(output, "\tp->stroke.color.type = SVG_COLOR_RGBCOLOR;\n"); + } else if (!strcmp("stroke-dasharray", att->svg_name)) { + fprintf(output, "\tp->stroke_dasharray.type = SVG_STROKEDASHARRAY_NONE;\n"); + } else if (!strcmp("stroke-dashoffset", att->svg_name)) { + fprintf(output, "\tp->stroke_dashoffset.type = SVG_NUMBER_VALUE;\n"); + } else if (!strcmp("stroke-linecap", att->svg_name)) { + fprintf(output, "\tp->stroke_linecap = SVG_STROKELINECAP_BUTT;\n"); + } else if (!strcmp("stroke-linejoin", att->svg_name)) { + fprintf(output, "\tp->stroke_linejoin = SVG_STROKELINEJOIN_MITER;\n"); + } else if (!strcmp("stroke-miterlimit", att->svg_name)) { + fprintf(output, "\tp->stroke_miterlimit.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->stroke_miterlimit.value = 4*FIX_ONE;\n"); + } else if (!strcmp("stroke-opacity", att->svg_name)) { + fprintf(output, "\tp->stroke_opacity.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->stroke_opacity.value = FIX_ONE;\n"); + } else if (!strcmp("stroke-width", att->svg_name)) { + fprintf(output, "\tp->stroke_width.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->stroke_width.value = FIX_ONE;\n"); + } else if (!strcmp("text-align", att->svg_name)) { + fprintf(output, "\tp->text_align = SVG_TEXTALIGN_START;\n"); + } else if (!strcmp("text-anchor", att->svg_name)) { + fprintf(output, "\tp->text_anchor = SVG_TEXTANCHOR_START;\n"); + } else if (!strcmp("vector-effect", att->svg_name)) { + fprintf(output, "\tp->vector_effect = SVG_VECTOREFFECT_NONE;\n"); + } else if (!strcmp("viewport-fill", att->svg_name)) { + fprintf(output, "\tp->viewport_fill.type = SVG_PAINT_NONE;\n"); + } else if (!strcmp("viewport-fill-opacity", att->svg_name)) { + fprintf(output, "\tp->viewport_fill_opacity.type = SVG_NUMBER_VALUE;\n"); + fprintf(output, "\tp->viewport_fill_opacity.value = FIX_ONE;\n"); + } else if (!strcmp("visibility", att->svg_name)) { + fprintf(output, "\tp->visibility = SVG_VISIBILITY_VISIBLE;\n"); + } + + /* Initialization of complex types */ + if ( !strcmp("SVG_Points", att->impl_type) || + !strcmp("SVG_Coordinates", att->impl_type) || + !strcmp("SMIL_KeyPoints", att->impl_type)) { + fprintf(output, "\tp->%s = gf_list_new();\n", att->implementation_name); + } else if (!strcmp("SVG_PathData", att->impl_type) && !strcmp(svg_elt->svg_name, "animateMotion")) { + fprintf(output, "#ifdef USE_GF_PATH\n"); + fprintf(output, "\tgf_path_reset(&p->path);\n"); + fprintf(output, "#else\n"); + fprintf(output, "\tp->path.commands = gf_list_new();\n"); + fprintf(output, "\tp->path.points = gf_list_new();\n"); + fprintf(output, "#endif\n"); + } else if (!strcmp("SVG_PathData", att->impl_type)) { + fprintf(output, "#ifdef USE_GF_PATH\n"); + fprintf(output, "\tgf_path_reset(&p->d);\n"); + fprintf(output, "#else\n"); + fprintf(output, "\tp->d.commands = gf_list_new();\n"); + fprintf(output, "\tp->d.points = gf_list_new();\n"); + fprintf(output, "#endif\n"); + } else if (!strcmp(att->svg_name, "lsr:enabled")) { + fprintf(output, "\tp->lsr_enabled = 1;\n"); + } + } + /*some default values*/ + if (!strcmp(svg_elt->svg_name, "svg")) { + fprintf(output, "\tp->width.type = SVG_NUMBER_PERCENTAGE;\n"); + fprintf(output, "\tp->width.value = INT2FIX(100);\n"); + fprintf(output, "\tp->height.type = SVG_NUMBER_PERCENTAGE;\n"); + fprintf(output, "\tp->height.value = INT2FIX(100);\n"); + } + else if (!strcmp(svg_elt->svg_name, "linearGradient")) { + fprintf(output, "\tp->x2.value = FIX_ONE;\n"); + fprintf(output, "\tgf_mx2d_init(p->gradientTransform.mat);\n"); + } + else if (!strcmp(svg_elt->svg_name, "radialGradient")) { + fprintf(output, "\tp->cx.value = FIX_ONE/2;\n"); + fprintf(output, "\tp->cy.value = FIX_ONE/2;\n"); + fprintf(output, "\tp->r.value = FIX_ONE/2;\n"); + fprintf(output, "\tgf_mx2d_init(p->gradientTransform.mat);\n"); + fprintf(output, "\tp->fx.value = FIX_ONE/2;\n"); + fprintf(output, "\tp->fy.value = FIX_ONE/2;\n"); + } + else if (!strcmp(svg_elt->svg_name, "video") || !strcmp(svg_elt->svg_name, "audio") || !strcmp(svg_elt->svg_name, "animation")) { + fprintf(output, "\tp->timing->dur.type = SMIL_DURATION_MEDIA;\n"); + } + fprintf(output, "\treturn p;\n}\n\n"); + + /* Destructor */ + fprintf(output, "static void gf_svg_sani_%s_del(GF_Node *node)\n{\n", svg_elt->implementation_name); + fprintf(output, "\tSVG_SANI_%sElement *p = (SVG_SANI_%sElement *)node;\n", svg_elt->implementation_name, svg_elt->implementation_name); + fprintf(output, "\tgf_svg_sani_reset_base_element((SVG_SANI_Element *)p);\n"); + + if (!strcmp(svg_elt->implementation_name, "conditional")) { + fprintf(output, "\tgf_svg_sa_reset_lsr_conditional(&p->updates);\n"); + } + else if (!strcmp(svg_elt->implementation_name, "a")) { + fprintf(output, "\tif (p->target) free(p->target);\n"); + } + + for (i = 0; i < gf_list_count(svg_elt->attributes); i++) { + SVGGenAttribute *att = gf_list_get(svg_elt->attributes, i); + if (!strcmp("SMIL_KeyPoints", att->impl_type)) { + fprintf(output, "\tgf_smil_delete_key_types(p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_Coordinates", att->impl_type)) { + fprintf(output, "\tgf_svg_delete_coordinates(p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_Points", att->impl_type)) { + fprintf(output, "\tgf_svg_delete_points(p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_PathData", att->impl_type)) { + if (!strcmp(svg_elt->svg_name, "animateMotion")) { + fprintf(output, "\tgf_svg_reset_path(p->path);\n"); + } else { + fprintf(output, "\tgf_svg_reset_path(p->d);\n"); + } + } else if (!strcmp("XMLRI", att->impl_type)) { + fprintf(output, "\tgf_svg_reset_iri(node->sgprivate->scenegraph, &p->%s);\n", att->implementation_name); + } else if (!strcmp("SVG_FontFamily", att->impl_type)) { + fprintf(output, "\tif (p->%s.value) free(p->%s.value);\n", att->implementation_name, att->implementation_name); + } else if (!strcmp("SVG_String", att->impl_type) || !strcmp("SVG_ContentType", att->impl_type)) { + fprintf(output, "\tfree(p->%s);\n", att->implementation_name); + } + } + if (svg_elt->has_transform) { + fprintf(output, "\tif (p->motionTransform) free(p->motionTransform);\n"); + } + + fprintf(output, "\tgf_sg_parent_reset((GF_Node *) p);\n"); + fprintf(output, "\tgf_node_free((GF_Node *)p);\n"); + fprintf(output, "}\n\n"); + + /* Attribute Access */ + fprintf(output, "static GF_Err gf_svg_sani_%s_get_attribute(GF_Node *node, GF_FieldInfo *info)\n{\n", svg_elt->implementation_name); + fprintf(output, "\tswitch (info->fieldIndex) {\n"); + svg_elt->nb_atts = 0; + svg_elt->nb_atts = generateCoreInfo(output, svg_elt, svg_elt->nb_atts); + + if (svg_elt->has_focus) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 4, "((SVG_SANI_Element *)node)->focus->", svg_elt->nb_atts); + if (svg_elt->has_xlink) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 5, "((SVG_SANI_Element *)node)->xlink->", svg_elt->nb_atts); + if (svg_elt->has_timing) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 6, "((SVG_SANI_Element *)node)->timing->", svg_elt->nb_atts); + if (svg_elt->has_sync) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 7, "((SVG_SANI_Element *)node)->sync->", svg_elt->nb_atts); + if (svg_elt->has_animation) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 8, "((SVG_SANI_Element *)node)->anim->", svg_elt->nb_atts); + if (svg_elt->has_conditional) + svg_elt->nb_atts = generateGenericInfo(output, svg_elt, 9, "((SVG_SANI_Element *)node)->conditional->", svg_elt->nb_atts); + if (svg_elt->has_transform) { + svg_elt->nb_atts = generateTransformInfo2(output, svg_elt, svg_elt->nb_atts); + svg_elt->nb_atts = generateMotionTransformInfo2(output, svg_elt, svg_elt->nb_atts); + } + if (svg_elt->has_xy) + svg_elt->nb_atts = generateXYInfo2(output, svg_elt, svg_elt->nb_atts); + + for (i = 0; i < gf_list_count(svg_elt->attributes); i++) { + SVGGenAttribute *att = gf_list_get(svg_elt->attributes, i); + generateAttributeInfo2(output, svg_elt->implementation_name, att, svg_elt->nb_atts++); + } + fprintf(output, "\t\tdefault: return GF_BAD_PARAM;\n\t}\n}\n\n"); + +} + +void generateSVGCode_V2(GF_List *svg_elements) +{ + FILE *output; + u32 i; + + output = BeginFile(0); + fprintf(output, "#include \n\n\n"); + fprintf(output, "/* Definition of SVG 2 Alternate element internal tags */\n"); + fprintf(output, "/* TAG names are made of \"TAG_SVG_SANI_\" + SVG element name (with - replaced by _) */\n"); + + /* write all tags */ + fprintf(output, "enum {\n"); + for (i=0; iimplementation_name); + } else { + fprintf(output, ",\n\tTAG_SVG_SANI_%s", elt->implementation_name); + } + } + + fprintf(output, ",\n\t/*undefined elements (when parsing) use this tag*/\n\tTAG_SVG_SANI_UndefinedElement\n};\n\n"); + + fprintf(output, "/******************************************\n"); + fprintf(output, "* SVG_SANI_ Elements structure definitions *\n"); + fprintf(output, "*******************************************/\n"); + for (i=0; i\n\n"); + + fprintf(output, "#ifndef GPAC_DISABLE_SVG\n\n"); + fprintf(output, "#include \n\n"); + for (i=0; iimplementation_name,elt->implementation_name); + } + fprintf(output, "\t\tdefault: return NULL;\n\t}\n}\n\n"); + + fprintf(output, "void gf_svg_sani_element_del(SVG_SANI_Element *elt)\n{\n"); + fprintf(output, "\tGF_Node *node = (GF_Node *)elt;\n"); + fprintf(output, "\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iimplementation_name, elt->implementation_name); + } + fprintf(output, "\t\tdefault: return;\n\t}\n}\n\n"); + + fprintf(output, "u32 gf_svg_sani_get_attribute_count(GF_Node *node)\n{\n"); + fprintf(output, "\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iimplementation_name, elt->nb_atts); + } + fprintf(output, "\t\tdefault: return 0;\n\t}\n}\n\n"); + + fprintf(output, "GF_Err gf_svg_sani_get_attribute_info(GF_Node *node, GF_FieldInfo *info)\n{\n"); + fprintf(output, "\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iimplementation_name, elt->implementation_name); + } + fprintf(output, "\t\tdefault: return GF_BAD_PARAM;\n\t}\n}\n\n"); + + fprintf(output, "u32 gf_svg_sani_type_by_class_name(const char *element_name)\n{\n\tif (!element_name) return TAG_UndefinedNode;\n"); + for (i=0; isvg_name, elt->implementation_name); + } + fprintf(output, "\treturn TAG_UndefinedNode;\n}\n\n"); + + fprintf(output, "const char *gf_svg_sani_get_element_name(u32 tag)\n{\n\tswitch(tag) {\n"); + for (i=0; iimplementation_name, elt->svg_name); + } + fprintf(output, "\tdefault: return \"UndefinedNode\";\n\t}\n}\n\n"); + + fprintf(output, "Bool gf_svg_sani_is_element_transformable(u32 tag)\n{\n\tswitch(tag) {\n"); + for (i=0; iimplementation_name); + if (elt->has_transform) fprintf(output, "return 1;\n"); + else fprintf(output, "return 0;\n"); + } + fprintf(output, "\tdefault: return 0;\n\t}\n}\n"); + + fprintf(output, "#endif /*GPAC_DISABLE_SVG*/\n\n"); + EndFile(output, 1); + + generate_laser_tables(svg_elements); +} diff --git a/applications/generators/SVG/v3.c b/applications/generators/SVG/v3.c new file mode 100644 index 0000000..9af75c3 --- /dev/null +++ b/applications/generators/SVG/v3.c @@ -0,0 +1,295 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2004-2012 + * All rights reserved + * + * This file is part of GPAC / SVG Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "svggen.h" + + +void buildGlobalAttributeList(GF_List *svg_elements, GF_List *all_atts) +{ + u32 i, j, k; + Bool added = 0; + + for (i=0; igeneric_attributes); j++) { + SVGGenAttribute *att = gf_list_get(elt->generic_attributes, j); + added = 0; + if (!strcmp(att->impl_type, "SMIL_Fill")) { + strcpy(att->implementation_name, "smil_fill"); + } else if (!strcmp(att->impl_type, "SVG_TransformType")) { + strcpy(att->implementation_name, "transform_type"); + } + for (k = 0; k < gf_list_count(all_atts); k++) { + SVGGenAttribute *a = gf_list_get(all_atts, k); + if (!strcmp(a->implementation_name, att->implementation_name) + && !strcmp(a->impl_type, att->impl_type)) { + added = 1; + break; + } + } + if (!added) { + gf_list_add(all_atts, att); + } + } + for (j = 0; j < gf_list_count(elt->attributes); j++) { + SVGGenAttribute *att = gf_list_get(elt->attributes, j); + added = 0; + if (!strcmp(elt->svg_name, "text")) { + if (!strcmp(att->implementation_name, "x")) { + strcpy(att->implementation_name, "text_x"); + } else if (!strcmp(att->implementation_name, "y")) { + strcpy(att->implementation_name, "text_y"); + } else if (!strcmp(att->implementation_name, "rotate")) { + strcpy(att->implementation_name, "text_rotate"); + } + } else if (!strcmp(elt->svg_name, "listener") && !strcmp(att->implementation_name, "target")) { + strcpy(att->implementation_name, "listener_target"); + } else if (!strcmp(elt->svg_name, "a") && !strcmp(att->implementation_name, "target")) { + strcpy(att->impl_type, "SVG_String"); + } else if (!strcmp(elt->svg_name, "cursorManager")) { + if (!strcmp(att->implementation_name, "x")) { + strcpy(att->implementation_name, "cursorManager_x"); + } else if (!strcmp(att->implementation_name, "y")) { + strcpy(att->implementation_name, "cursorManager_y"); + } + } + for (k = 0; k < gf_list_count(all_atts); k++) { + SVGGenAttribute *a = gf_list_get(all_atts, k); + if (!strcmp(a->implementation_name, att->implementation_name) + && !strcmp(a->impl_type, att->impl_type)) { + added = 1; + break; + } + } + if (!added) { + gf_list_add(all_atts, att); + } + } + } + /*motionTransform is not parsed in rng*/ + { + SVGGenAttribute *att = NewSVGGenAttribute(); + strcpy(att->implementation_name, "motionTransform"); + strcpy(att->impl_type, "SVG_Motion"); + att->svg_name = "motionTransform"; + att->svg_type = "SVG_Motion"; + gf_list_add(all_atts, att); + } +} + +void generateSVGCode_V3(GF_List *svg_elements) +{ + FILE *output; + u32 i; + GF_List *all_atts = gf_list_new(); + + buildGlobalAttributeList(svg_elements, all_atts); + + /***************************************************/ + /***************************************************/ + /*************** Creating .h file ******************/ + /***************************************************/ + /***************************************************/ + output = BeginFile(0); + fprintf(output, "#include \n\n\n"); + + /* Generation of ELEMENT tags */ + fprintf(output, "/* Definition of SVG 3 Alternate element internal tags */\n"); + fprintf(output, "/* TAG names are made of \"TAG_SVG\" + SVG element name (with - replaced by _) */\n"); + fprintf(output, "enum {\n"); + for (i=0; iimplementation_name); + } else { + fprintf(output, ",\n\tTAG_SVG_%s", elt->implementation_name); + } + } + fprintf(output, ",\n\t/*undefined elements (when parsing) use this tag*/\n\tTAG_SVG_UndefinedElement\n};\n\n"); + + /* Generation of ATTRIBUTE tags */ + fprintf(output, "/* Definition of SVG 3 attribute internal tags - %d defined */\n", gf_list_count(all_atts)); + fprintf(output, "/* TAG names are made of \"TAG_SVG_ATT_\" + SVG attribute name (with - replaced by _) */\n"); + fprintf(output, "enum {\n"); + + for (i=0; iimplementation_name); + else fprintf(output, "\tTAG_SVG_ATT_%s = TAG_SVG_ATT_RANGE_FIRST,\n", att->implementation_name); + } + fprintf(output, "\t/*undefined attributes (when parsing) use this tag*/\n\tTAG_SVG_ATT_Unknown\n};\n\n"); + + /* Generation of the flatten structure pointing to all possible attributes in SVG */ + fprintf(output, "struct _all_atts {\n"); + for (i=0; iimpl_type, att->implementation_name); + } + fprintf(output, "};\n"); + + EndFile(output, 0); + + /***************************************************/ + /***************************************************/ + /*************** Creating .c file ******************/ + /***************************************************/ + /***************************************************/ + output = BeginFile(1); + fprintf(output, "#ifndef GPAC_DISABLE_SVG\n\n"); + fprintf(output, "#include \n\n"); + fprintf(output, "#include \n\n"); + + + /****************************************************************/ + /* u32 gf_svg_get_attribute_tag(u32 element_tag, const char *attribute_name) */ + /****************************************************************/ + fprintf(output, "u32 gf_svg_get_attribute_tag(u32 element_tag, const char *attribute_name)\n{\n\tif (!attribute_name) return TAG_SVG_ATT_Unknown;\n"); + for (i=0; iimpl_type, "SMIL_Fill")) continue; + if (!strcmp(att->impl_type, "SVG_ContentType")) continue; + if (!strcmp(att->implementation_name, "text_x")) continue; + if (!strcmp(att->implementation_name, "text_y")) continue; + if (!strcmp(att->implementation_name, "text_rotate")) continue; + if (!strcmp(att->implementation_name, "cursorManager_x")) continue; + if (!strcmp(att->implementation_name, "cursorManager_y")) continue; + + if (!strcmp(att->svg_name, "x") || !strcmp(att->svg_name, "y")) { + fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); + fprintf(output, "\t\tif (element_tag == TAG_SVG_text) return TAG_SVG_ATT_text_%s;\n", att->implementation_name); + fprintf(output, "\t\telse if (element_tag == TAG_SVG_cursorManager) return TAG_SVG_ATT_cursorManager_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t}\n"); + } else if (!strcmp(att->svg_name, "rotate")) { + fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); + fprintf(output, "\t\tif (element_tag == TAG_SVG_text) return TAG_SVG_ATT_text_%s;\n", att->implementation_name); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t}\n"); + } else if (!strcmp(att->svg_name, "type")) { + fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); + fprintf(output, "\t\tif (element_tag == TAG_SVG_animateTransform) return TAG_SVG_ATT_transform_type;\n"); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t}\n"); + } else if (!strcmp(att->svg_name, "fill")) { + fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); + fprintf(output, "\t\tif (element_tag == TAG_SVG_animate || element_tag == TAG_SVG_animateColor || element_tag == TAG_SVG_animateMotion || element_tag == TAG_SVG_animateTransform || element_tag == TAG_SVG_animation || element_tag == TAG_SVG_audio || element_tag == TAG_SVG_video || element_tag == TAG_SVG_set) return TAG_SVG_ATT_smil_fill;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t}\n"); + } else { + fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + } + } + fprintf(output, "\treturn TAG_SVG_ATT_Unknown;\n}\n\n"); + + /****************************************************************/ + /* u32 gf_svg_get_attribute_type(u32 tag) */ + /****************************************************************/ + fprintf(output, "u32 gf_svg_get_attribute_type(u32 tag)\n{\n"); + fprintf(output, "\tswitch(tag) {\n"); + for (i=0; iimplementation_name, att->impl_type); + } + fprintf(output, "\t\tdefault: return SVG_Unknown_datatype;\n"); + fprintf(output, "\t}\n"); + fprintf(output, "\treturn TAG_SVG_ATT_Unknown;\n}\n\n"); + + /****************************************************************/ + /* const char* gf_svg_get_attribute_name(u32 tag) */ + /****************************************************************/ + fprintf(output, "const char*gf_svg_get_attribute_name(u32 tag)\n{\n"); + fprintf(output, "\tswitch(tag) {\n"); + for (i=0; iimplementation_name, att->svg_name); + } + fprintf(output, "\t\tdefault: return \"unknown\";\n"); + fprintf(output, "\t}\n"); + fprintf(output, "}\n\n"); + + /***************************************************/ + /* SVGAttribute *gf_svg_create_attribute(GF_Node *node, u32 tag) */ + /***************************************************/ + fprintf(output, "SVGAttribute *gf_svg_create_attribute(GF_Node *node, u32 tag)\n{\n\tswitch(tag) {\n"); + for (i=0; iimplementation_name, att->impl_type); + } + fprintf(output, "\tdefault: return NULL;\n\t}\n}\n\n"); + + /****************************************************************/ + /* void gf_svg_flatten_attributes(SVG_Element *e, SVGAllAttributes *all_atts) */ + /****************************************************************/ + fprintf(output, "void gf_svg_flatten_attributes(SVG_Element *e, SVGAllAttributes *all_atts)\n"); + + fprintf(output, "{\n"); + fprintf(output, "\tSVGAttribute *att;\n"); + fprintf(output, "\tmemset(all_atts, 0, sizeof(SVGAllAttributes));\n"); + fprintf(output, "\tif (e->sgprivate->tag <= GF_NODE_FIRST_DOM_NODE_TAG) return;\n"); + fprintf(output, "\tatt = e->attributes;\n"); + fprintf(output, "\twhile (att) {\n"); + fprintf(output, "\t\tswitch(att->tag) {\n"); + for (i=0; i%s = (%s *)att->data; break;\n", att->implementation_name, att->implementation_name, att->impl_type); + } + fprintf(output, "\t\t}\n"); + fprintf(output, "\tatt = att->next;\n"); + fprintf(output, "\t}\n"); + fprintf(output, "}\n"); + fprintf(output, "\n"); + + /****************************************************************/ + /* u32 gf_svg_get_element_tag(const char *element_name) */ + /****************************************************************/ + fprintf(output, "u32 gf_svg_get_element_tag(const char *element_name)\n{\n\tif (!element_name) return TAG_UndefinedNode;\n"); + for (i=0; isvg_name, elt->implementation_name); + } + fprintf(output, "\treturn TAG_UndefinedNode;\n}\n\n"); + + /***************************************************/ + /* const char *gf_svg_get_element_name(u32 tag) */ + /***************************************************/ + fprintf(output, "const char *gf_svg_get_element_name(u32 tag)\n{\n\tswitch(tag) {\n"); + for (i=0; iimplementation_name, elt->svg_name); + } + fprintf(output, "\tdefault: return \"TAG_SVG_UndefinedNode\";\n\t}\n}\n\n"); + + fprintf(output, "#endif /*GPAC_DISABLE_SVG*/\n\n"); + EndFile(output, 1); + + + generate_laser_tables_da(all_atts); + + gf_list_del(all_atts); + +} + diff --git a/applications/generators/X3D/Makefile b/applications/generators/X3D/Makefile new file mode 100644 index 0000000..1a96c0e --- /dev/null +++ b/applications/generators/X3D/Makefile @@ -0,0 +1,52 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/generators/X3D + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=X3DGen$(EXE) +else +EXT= +PROG=X3DGen +endif + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac + + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + + +clean: + rm -f $(OBJS) $(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/generators/X3D/X3DGen.dsp b/applications/generators/X3D/X3DGen.dsp new file mode 100644 index 0000000..7afd243 --- /dev/null +++ b/applications/generators/X3D/X3DGen.dsp @@ -0,0 +1,98 @@ +# Microsoft Developer Studio Project File - Name="X3DGen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=X3DGen - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "X3DGen.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "X3DGen.mak" CFG="X3DGen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "X3DGen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "X3DGen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "X3DGen - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "X3DGen - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Obj/W32Deb" +# PROP Intermediate_Dir "Obj/W32Deb" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "X3DGen - Win32 Release" +# Name "X3DGen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\utils\list.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# End Target +# End Project diff --git a/applications/generators/X3D/X3DGen.dsw b/applications/generators/X3D/X3DGen.dsw new file mode 100644 index 0000000..2aca071 --- /dev/null +++ b/applications/generators/X3D/X3DGen.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "X3DGen"=.\X3DGen.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/generators/X3D/main.c b/applications/generators/X3D/main.c new file mode 100644 index 0000000..339819a --- /dev/null +++ b/applications/generators/X3D/main.c @@ -0,0 +1,1279 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2000-2012 + * All rights reserved + * + * This file is part of GPAC / X3D Scene Graph Generator sub-project + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +#include +#include + +#define COPYRIGHT "/*\n * GPAC - Multimedia Framework C SDK\n *\n * Authors: Jean Le Feuvre\n * Copyright (c) Telecom ParisTech 2000-2012\n * All rights reserved\n *\n * This file is part of GPAC / X3D Scene Graph sub-project\n *\n * GPAC is free software; you can redistribute it and/or modify\n * it under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2, or (at your option)\n * any later version.\n *\n * GPAC is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details. \n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; see the file COPYING. If not, write to\n * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n" + +static char *CurrentLine; + +void PrintUsage() +{ + printf("X3DGen [skip_file]\n" + "\nGPAC X3D Scene Graph generator\n" + "\n" + "\nskip_file: txt file with list of nodes to leave unimplemented" + "Generated Files are directly updated in the GPAC distribution - do NOT try to change this\n\n" + "Written by Jean Le Feuvre - (c) 2000-2005\n" + ); +} + +//a node field +typedef struct +{ + char type[50]; + //SFxxx, MFxxx + char familly[50]; + //name + char name[1000]; + //default value + char def[100]; + //bounds + u32 hasBounds; + char b_min[20]; + char b_max[20]; +} X3DField; + +//NDTs + +//a BIFS node +typedef struct +{ + char name[1000]; + //NDT info. NDT are created in alphabetical order + GF_List *NDT; + GF_List *Fields; + u8 hasDefault; + char Child_NDT_Name[1000]; + u8 skip_impl; + +} X3DNode; + + +void skip_sep(char *sep) +{ + //skip separaors + while (*CurrentLine && strchr(sep, *CurrentLine)) { + CurrentLine = CurrentLine + 1; + //end of line - no token + if (*CurrentLine == '\n') return; + } +} + +//note that we increment the line no matter what +u32 GetNextToken(char *token, char *sep) +{ + u32 i , j = 0; + + strcpy(token, ""); + + //skip separaors + while (*CurrentLine && strchr(sep, *CurrentLine)) { + CurrentLine = CurrentLine + 1; + j ++; + //end of line - no token + if (*CurrentLine == '\n') return 0; + } + + //copy token untill next blank + i=0; + while (1) { + //bad line + if (! *CurrentLine) { + token[i] = 0; + return 0; + } + //end of token or end of line + if (strchr(sep, *CurrentLine) || (*CurrentLine == '\n') ) { + token[i] = 0; + CurrentLine = CurrentLine + 1; + return i; + } else { + token[i] = *CurrentLine; + } + CurrentLine = CurrentLine + 1; + i++; + j++; + } + return 1; +} + +X3DField *BlankField() +{ + X3DField *n = gf_malloc(sizeof(X3DField)); + memset(n, 0, sizeof(X3DField)); + return n; +} + + +X3DNode *BlankNode() +{ + X3DNode *n = gf_malloc(sizeof(X3DNode)); + memset(n, 0, sizeof(X3DNode)); + n->NDT = gf_list_new(); + n->Fields = gf_list_new(); + return n; +} + +u8 IsNDT(GF_List *NDTs, char *famName) +{ + u32 i; + char *ndtName; + for (i=0; i\n\n"); + fprintf(f, "#ifndef GPAC_DISABLE_X3D\n\n"); + + //write all tags + fprintf(f, "\n\nenum {\n"); + + for (i=0; iname); + else + fprintf(f, "\tTAG_X3D_%s = GF_NODE_RANGE_FIRST_X3D", n->name); + } + fprintf(f, ",\n\tTAG_LastImplementedX3D\n};\n\n"); + + for (i=0; iskip_impl) continue; + fprintf(f, "typedef struct _tagX3D%s\n{\n", n->name); + fprintf(f, "\tBASE_NODE\n"); + + /*write children field*/ + for (j=0; jFields); j++) { + bf = gf_list_get(n->Fields, j); + if (!stricmp(bf->name, "addChildren") || !strcmp(bf->name, "removeChildren")) continue; + if (strcmp(bf->type, "eventOut") && !strcmp(bf->name, "children")) { + fprintf(f, "\tVRML_CHILDREN\n"); + break; + } + } + for (j=0; jFields); j++) { + bf = gf_list_get(n->Fields, j); + + if (!strcmp(bf->name, "addChildren") || !strcmp(bf->name, "removeChildren")) continue; + if (strcmp(bf->type, "eventOut") && !strcmp(bf->name, "children")) continue; + + if (strstr(bf->familly, "Node")) { + //this is a POINTER to a node + if (strstr(bf->familly, "SF")) { + fprintf(f, "\tGF_Node *%s;\t/*%s*/\n", bf->name, bf->type); + } else { + //this is a POINTER to a chain + fprintf(f, "\tGF_ChildNodeItem *%s;\t/*%s*/\n", bf->name, bf->type); + } + } else { + fprintf(f, "\t%s %s;\t/*%s*/\n", bf->familly, bf->name, bf->type); + } + if (!strcmp(bf->type, "eventIn")) + fprintf(f, "\tvoid (*on_%s)(GF_Node *pThis, struct _route *route);\t/*eventInHandler*/\n", bf->name); + } + fprintf(f, "} X_%s;\n\n\n", n->name); + } + + fprintf(f, "#endif /*GPAC_DISABLE_X3D*/\n\n"); + EndFile(f, 0); + +} + +void WriteNodeFields(FILE *f, X3DNode *n) +{ + u32 i; + X3DField *bf; + + fprintf(f, "\nstatic u32 %s_get_field_count(GF_Node *node, u8 dummy)\n{\n\treturn %d;\n}\n\n", n->name, gf_list_count(n->Fields)); + fprintf(f, "static GF_Err %s_get_field(GF_Node *node, GF_FieldInfo *info)\n{\n\tswitch (info->fieldIndex) {\n", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + + fprintf(f, "\tcase %d:\n", i); + + fprintf(f, "\t\tinfo->name = \"%s\";\n", bf->name); + + //skip all eventIn + if (!strcmp(bf->type, "eventIn")) { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_IN;\n"); + fprintf(f, "\t\tinfo->on_event_in = ((X_%s *)node)->on_%s;\n", n->name, bf->name); + } + else if (!strcmp(bf->type, "eventOut")) { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_OUT;\n"); + } + else if (!strcmp(bf->type, "field")) { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_FIELD;\n"); + } + else { + fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_EXPOSED_FIELD;\n"); + } + + if (strstr(bf->familly, "Node")) { + if (strstr(bf->familly, "MF")) { + fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_MFNODE;\n"); + } else { + fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_SFNODE;\n"); + } + //always remove the SF or MF, as all NDTs are SFXXX + fprintf(f, "\t\tinfo->NDTtype = NDT_SF%s;\n", bf->familly+2); + fprintf(f, "\t\tinfo->far_ptr = & ((X_%s *)node)->%s;\n", n->name, bf->name); + } else { + char szName[20]; + strcpy(szName, bf->familly); + strupr(szName); + //no ext type + fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_%s;\n", szName); + fprintf(f, "\t\tinfo->far_ptr = & ((X_%s *) node)->%s;\n", n->name, bf->name); + } + fprintf(f, "\t\treturn GF_OK;\n"); + } + fprintf(f, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n"); + + fprintf(f, "\nstatic s32 %s_get_field_index_by_name(char *name)\n{\n", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + fprintf(f, "\tif (!strcmp(\"%s\", name)) return %d;\n", bf->name, i); + } + fprintf(f, "\treturn -1;\n\t}\n"); +} + +void WriteNodeCode(GF_List *BNodes, FILE *vrml_code) +{ + char token[20], tok[20]; + char *store; + u32 i, j, k, go; + X3DField *bf; + X3DNode *n; + + fprintf(vrml_code, "\n#include \n"); + fprintf(vrml_code, "\n#include \n"); + fprintf(vrml_code, "\n/*for NDT tag definitions*/\n#include \n"); + fprintf(vrml_code, "#ifndef GPAC_DISABLE_X3D\n\n"); + + for (k=0; kskip_impl) continue; + fprintf(vrml_code, "\n/*\n\t%s Node deletion\n*/\n\n", n->name); + fprintf(vrml_code, "static void %s_Del(GF_Node *node)\n{\n\tX_%s *p = (X_%s *) node;\n", n->name, n->name, n->name); + + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + //nothing on child events + if (!strcmp(bf->name, "addChildren")) continue; + if (!strcmp(bf->name, "removeChildren")) continue; + + //delete all children node + if (strcmp(bf->type, "eventOut") && !strcmp(bf->name, "children")) { + is_parent = 1; + continue; + } + + //delete ALL fields that must be deleted: this includes eventIn and out since + //all fields are defined in the node + if (!strcmp(bf->familly, "MFInt") + || !strcmp(bf->familly, "MFFloat") + || !strcmp(bf->familly, "MFDouble") + || !strcmp(bf->familly, "MFBool") + || !strcmp(bf->familly, "MFInt32") + || !strcmp(bf->familly, "MFColor") + || !strcmp(bf->familly, "MFRotation") + || !strcmp(bf->familly, "MFString") + || !strcmp(bf->familly, "MFTime") + || !strcmp(bf->familly, "MFVec2f") + || !strcmp(bf->familly, "MFVec3f") + || !strcmp(bf->familly, "MFVec4f") + || !strcmp(bf->familly, "MFVec2d") + || !strcmp(bf->familly, "MFVec3d") + || !strcmp(bf->familly, "MFURL") + || !strcmp(bf->familly, "MFScript") + || !strcmp(bf->familly, "SFString") + || !strcmp(bf->familly, "SFURL") + || !strcmp(bf->familly, "SFImage") + + ) { + char szName[500]; + strcpy(szName, bf->familly); + strlwr(szName); + fprintf(vrml_code, "\tgf_sg_%s_del(p->%s);\n", szName, bf->name); + } else if (strstr(bf->familly, "Node")) { + //this is a POINTER to a node + if (strstr(bf->familly, "SF")) { + fprintf(vrml_code, "\tgf_node_unregister((GF_Node *) p->%s, node);\t\n", bf->name); + } else { + //this is a POINTER to a chain + fprintf(vrml_code, "\tgf_node_unregister_children(node, p->%s);\t\n", bf->name); + } + } + } + if (is_parent) + fprintf(vrml_code, "\tgf_sg_vrml_parent_destroy(node);\t\n"); + /*avoids gcc warnings in case no field to delete*/ + fprintf(vrml_code, "\tgf_node_free((GF_Node *)p);\n}\n\n"); + + //node fields + WriteNodeFields(vrml_code, n); + + // + // Constructor + // + + fprintf(vrml_code, "\n\nstatic GF_Node *%s_Create()\n{\n\tX_%s *p;\n\tGF_SAFEALLOC(p, X_%s);\n", n->name, n->name, n->name); + fprintf(vrml_code, "\tif(!p) return NULL;\n"); + fprintf(vrml_code, "\tgf_node_setup((GF_Node *)p, TAG_X3D_%s);\n", n->name); + + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + //setup all children node + if (strcmp(bf->type, "eventOut") && !strcmp(bf->name, "children")) { + fprintf(vrml_code, "\tgf_sg_vrml_parent_setup((GF_Node *) p);\n"); + break; + } + else if ( strstr(bf->familly, "Node") && strncmp(bf->type, "event", 5) ) { + //this is a POINTER to a node + if (strstr(bf->familly, "MF")) { + //this is a POINTER to a chain + //fprintf(vrml_code, "\tp->%s = gf_list_new();\t\n", bf->name); + } + } + /*special case for SFCommandBuffer: we also create a command list*/ + if (!stricmp(bf->familly, "SFCommandBuffer")) { + fprintf(vrml_code, "\tp->%s.commandList = gf_list_new();\t\n", bf->name); + } + } + + fprintf(vrml_code, "\n\t/*default field values*/\n"); + + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + + //nothing on eventIn or Out + if (!strcmp(bf->type, "eventIn")) continue; + if (!strcmp(bf->type, "eventOut")) continue; + + if (!strcmp(bf->def, "")) continue; + + //no default on nodes + if (strstr(bf->familly, "Node")) continue; + //extract default falue + + // + // SF Fields + // + + //SFBool + if (!strcmp(bf->familly, "SFBool")) { + if (!strcmp(bf->def, "1") || !strcmp(bf->def, "TRUE")) + fprintf(vrml_code, "\tp->%s = 1;\n", bf->name); + } + //SFFloat + else if (!strcmp(bf->familly, "SFFloat")) { + fprintf(vrml_code, "\tp->%s = FLT2FIX(%s);\n", bf->name, bf->def); + } + //SFDouble + else if (!strcmp(bf->familly, "SFDouble")) { + fprintf(vrml_code, "\tp->%s = (SFDouble) %s;\n", bf->name, bf->def); + } + //SFTime + else if (!strcmp(bf->familly, "SFTime")) { + fprintf(vrml_code, "\tp->%s = %s;\n", bf->name, bf->def); + } + //SFInt32 + else if (!strcmp(bf->familly, "SFInt32")) { + fprintf(vrml_code, "\tp->%s = %s;\n", bf->name, bf->def); + } + //SFColor + else if (!strcmp(bf->familly, "SFColor")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + + fprintf(vrml_code, "\tp->%s.red = FLT2FIX(%s);\n", bf->name, token); + GetNextToken(token, " "); + fprintf(vrml_code, "\tp->%s.green = FLT2FIX(%s);\n", bf->name, token); + GetNextToken(token, " "); + fprintf(vrml_code, "\tp->%s.blue = FLT2FIX(%s);\n", bf->name, token); + } + //SFVec2f + else if (!strcmp(bf->familly, "SFVec2f")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.x = FLT2FIX(%s);\n", bf->name, token); + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.y = FLT2FIX(%s);\n", bf->name, token); + } + //SFVec2d + else if (!strcmp(bf->familly, "SFVec2d")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.x = (SFDouble) %s;\n", bf->name, token); + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.y = (SFDouble) %s;\n", bf->name, token); + } + //SFVec3f + else if (!strcmp(bf->familly, "SFVec3f")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.x = FLT2FIX(%s);\n", bf->name, token); + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.y = FLT2FIX(%s);\n", bf->name, token); + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.z = FLT2FIX(%s);\n", bf->name, token); + } + //SFVec3d + else if (!strcmp(bf->familly, "SFVec3d")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.x = (SFDouble) %s;\n", bf->name, token); + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.y = (SFDouble) %s;\n", bf->name, token); + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.z = (SFDouble) %s;\n", bf->name, token); + } + //SFVec4f & SFRotation + else if (!strcmp(bf->familly, "SFVec4f") || !strcmp(bf->familly, "SFRotation")) { + CurrentLine = bf->def; + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.x = FLT2FIX(%s);\n", bf->name, token); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.y = FLT2FIX(%s);\n", bf->name, token); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.z = FLT2FIX(%s);\n", bf->name, token); + + GetNextToken(token, " "); + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.q = FLT2FIX(%s);\n", bf->name, token); + } + //SFString + else if (!strcmp(bf->familly, "SFString")) { + fprintf(vrml_code, "\tp->%s.buffer = (char*) gf_malloc(sizeof(char) * %d);\n", bf->name, strlen(bf->def)+1); + fprintf(vrml_code, "\tstrcpy(p->%s.buffer, \"%s\");\n", bf->name, bf->def); + } + + // + // MF Fields + // + //MFFloat + else if (!strcmp(bf->familly, "MFFloat")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, " ,")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFFloat *)gf_malloc(sizeof(SFFloat)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, " ,")) go = 0; + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.vals[%d] = FLT2FIX(%s);\n", bf->name, j, token); + j+=1; + } + } + //MFDouble + else if (!strcmp(bf->familly, "MFDouble")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, " ,")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFFloat*)gf_malloc(sizeof(SFFloat)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, " ,")) go = 0; + TranslateToken(token); + fprintf(vrml_code, "\tp->%s.vals[%d] = (SFDouble) %s;\n", bf->name, j, token); + j+=1; + } + } + //MFVec2f + else if (!strcmp(bf->familly, "MFVec2f")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFVec2f*) gf_malloc(sizeof(SFVec2f)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].x = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].y = FLT2FIX(%s);\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFVec2d + else if (!strcmp(bf->familly, "MFVec2d")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFVec2f*)gf_malloc(sizeof(SFVec2f)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].x = (SFDouble) %s;\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].y = (SFDouble) %s;\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFVec3f + else if (!strcmp(bf->familly, "MFVec3f")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFVec3f*)gf_malloc(sizeof(SFVec3f)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].x = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].y = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].z = FLT2FIX(%s);\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFVec3d + else if (!strcmp(bf->familly, "MFVec3d")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFVec2f*)gf_malloc(sizeof(SFVec3f)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].x = (SFDouble) %s;\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].y = (SFDouble) %s;\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].z = (SFDouble) %s;\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFVec4f & MFRotation + else if (!strcmp(bf->familly, "MFVec4f") || !strcmp(bf->familly, "MFRotation")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (GF_Vec4*)gf_malloc(sizeof(GF_Vec4)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].x = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].y = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].z = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d].q = FLT2FIX(%s);\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFInt32 + else if (!strcmp(bf->familly, "MFInt32")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFInt32*)gf_malloc(sizeof(SFInt32)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + fprintf(vrml_code, "\tp->%s.vals[%d] = %s;\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFColor + else if (!strcmp(bf->familly, "MFColor")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFColor*)gf_malloc(sizeof(SFColor)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " "); + fprintf(vrml_code, "\tp->%s.vals[%d].red = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + fprintf(vrml_code, "\tp->%s.vals[%d].green = FLT2FIX(%s);\n", bf->name, j, tok); + GetNextToken(tok, " "); + fprintf(vrml_code, "\tp->%s.vals[%d].blue = FLT2FIX(%s);\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFString + else if (!strcmp(bf->familly, "MFString")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (char**)gf_malloc(sizeof(SFString)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " \""); + fprintf(vrml_code, "\tp->%s.vals[%d] = (char*)gf_malloc(sizeof(char) * %d);\n", bf->name, j, strlen(tok)+1); + fprintf(vrml_code, "\tstrcpy(p->%s.vals[%d], \"%s\");\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + //MFTime + else if (!strcmp(bf->familly, "MFTime")) { + j = 0; + CurrentLine = bf->def; + while (GetNextToken(token, ",")) j++; + j+=1; + fprintf(vrml_code, "\tp->%s.vals = (SFTime*)gf_malloc(sizeof(SFTime)*%d);\n", bf->name, j); + fprintf(vrml_code, "\tp->%s.count = %d;\n", bf->name, j); + j = 0; + go = 1; + CurrentLine = bf->def; + while (go) { + if (!GetNextToken(token, ",")) go = 0; + store = CurrentLine; + CurrentLine = token; + GetNextToken(tok, " \""); + TranslateToken(tok); + fprintf(vrml_code, "\tp->%s.vals[%d] = %s;\n", bf->name, j, tok); + j+=1; + CurrentLine = store; + } + } + + //other nodes + else if (!strcmp(bf->familly, "SFImage")) { + //we currently only have SFImage, with NO texture so do nothing + } + //unknown init (for debug) + else { + fprintf(vrml_code, "UNKNOWN FIELD (%s);\n", bf->familly); + + } + } + fprintf(vrml_code, "\treturn (GF_Node *)p;\n}\n\n"); + + } + + fprintf(vrml_code, "\n\n\n"); + + //creator function + fprintf(vrml_code, "GF_Node *gf_sg_x3d_node_new(u32 NodeTag)\n{\n\tswitch (NodeTag) {\n"); + for (i=0; iskip_impl) fprintf(vrml_code, "\tcase TAG_X3D_%s:\n\t\treturn %s_Create();\n", n->name, n->name); + } + fprintf(vrml_code, "\tdefault:\n\t\treturn NULL;\n\t}\n}\n\n"); + + fprintf(vrml_code, "const char *gf_sg_x3d_node_get_class_name(u32 NodeTag)\n{\n\tswitch (NodeTag) {\n"); + for (i=0; iskip_impl) fprintf(vrml_code, "\tcase TAG_X3D_%s:\n\t\treturn \"%s\";\n", n->name, n->name); + } + fprintf(vrml_code, "\tdefault:\n\t\treturn \"Unknown Node\";\n\t}\n}\n\n"); + + fprintf(vrml_code, "void gf_sg_x3d_node_del(GF_Node *node)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) fprintf(vrml_code, "\tcase TAG_X3D_%s:\n\t\t%s_Del(node); return;\n", n->name, n->name); + } + fprintf(vrml_code, "\tdefault:\n\t\treturn;\n\t}\n}\n\n"); + + fprintf(vrml_code, "u32 gf_sg_x3d_node_get_field_count(GF_Node *node)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) fprintf(vrml_code, "\tcase TAG_X3D_%s:return %s_get_field_count(node, 0);\n", n->name, n->name); + } + fprintf(vrml_code, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n"); + + fprintf(vrml_code, "GF_Err gf_sg_x3d_node_get_field(GF_Node *node, GF_FieldInfo *field)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) fprintf(vrml_code, "\tcase TAG_X3D_%s: return %s_get_field(node, field);\n", n->name, n->name); + } + fprintf(vrml_code, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n"); + + fprintf(vrml_code, "\nu32 gf_node_x3d_type_by_class_name(const char *node_name)\n{\n\tif(!node_name) return 0;\n"); + for (i=0; iskip_impl) fprintf(vrml_code, "\tif (!strcmp(node_name, \"%s\")) return TAG_X3D_%s;\n", n->name, n->name); + } + fprintf(vrml_code, "\treturn 0;\n}\n\n"); + + fprintf(vrml_code, "s32 gf_sg_x3d_node_get_field_index_by_name(GF_Node *node, char *name)\n{\n\tswitch (node->sgprivate->tag) {\n"); + for (i=0; iskip_impl) { + fprintf(vrml_code, "\tcase TAG_X3D_%s: return %s_get_field_index_by_name(name);\n", n->name, n->name); + } + } + fprintf(vrml_code, "\tdefault:\n\t\treturn -1;\n\t}\n}\n\n"); + +} + + +static u32 IsNodeInTable(X3DNode *node, char *NDTName) +{ + u32 i; + char *ndt; + + for (i=0; iNDT); i++) { + ndt = gf_list_get(node->NDT, i); + if (!strcmp(ndt, NDTName)) return 1; + } + return 0; +} + +static u32 GetNDTCount(char *NDTName, GF_List *XNodes) +{ + u32 i, nodeCount; + X3DNode *n; + nodeCount = 0; + for (i=0; iname); + first = 0; + } else { + fprintf(f, ", TAG_X3D_%s", n->name); + } + } + fprintf(f, "\n};\n\n"); + } + + //NodeTag complete translation + fprintf(f, "\n\n\nBool gf_x3d_get_node_type(u32 NDT_Tag, u32 NodeTag)\n{\n\tconst u32 *types;\n\tu32 count, i;\n\tif (!NodeTag) return 0;\n\ttypes = NULL; count = 0;\n"); + + fprintf(f, "\tswitch (NDT_Tag) {\n"); + for (i=0; iname, " \t["); + + //extract the NDTs + GetNextToken(token, "\t[ %#="); + if (strcmp(token, "NDT")) { + printf("Corrupted template file\n"); + return; + } + while (1) { + GetNextToken(token, "=, \t"); + //done with NDTs + if (!token[0]) break; + + //update the NDT list + CheckInTable(token, NDTs); + p = gf_malloc(strlen(token)+1); + strcpy(p, token); + gf_list_add(n->NDT, p); + } + } + //this is NOT a field + else if (token[0] == ']' || token[0] == '{' || token[0] == '}' ) { + break; + } + //parse a field + else { + if (!n) { + printf("Corrupted template file\n"); + return; + } + f = BlankField(); + gf_list_add(n->Fields, f); + + //get the field type + strcpy(f->type, token); + GetNextToken(f->familly, " \t"); + GetNextToken(f->name, " \t"); + //fix for our own code :( + if (!strcmp(f->name, "tag")) strcpy(f->name, "_tag"); + + //has default + skip_sep(" \t"); + if (GetNextToken(token, "#\t")) { + j=0; + while (token[j] == ' ') j+=1; + if (token[j] == '[') j+=1; + if (token[j] == '"') j+=1; + + if (token[j] != '"' && token[j] != ']') { + strcpy(f->def, token+j); + j=1; + while (j) { + switch (f->def[strlen(f->def)-1]) { + case ' ': + case '"': + case ']': + f->def[strlen(f->def)-1] = 0; + break; + default: + j=0; + break; + } + } + } else { + strcpy(f->def, ""); + } + if (!strcmp(f->familly, "SFFloat")) { + if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) { + strcpy(f->def, "GF_MAX_FLOAT"); + } else if (!strcmp(f->def, "-I")) { + strcpy(f->def, "GF_MIN_FLOAT"); + } + } else if (!strcmp(f->familly, "SFTime")) { + if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) { + strcpy(f->def, "GF_MAX_FLOAT"); + } else if (!strcmp(f->def, "-I")) { + strcpy(f->def, "GF_MIN_FLOAT"); + } + } else if (!strcmp(f->familly, "SFInt32")) { + if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) { + strcpy(f->def, "2 << 31"); + } else if (!strcmp(f->def, "-I")) { + strcpy(f->def, "- (2 << 31)"); + } + } + } + //has other + while (GetNextToken(token, " \t#%=")) { + switch (token[0]) { + //bounds + case 'b': + case 'q': + case 'a': + printf("Corrupted X3D template file (quantization/animation not allowed)\n"); + gf_list_del_item(n->Fields, f); + gf_free(f); + return; + default: + break; + } + } + /*we ignore these*/ + if (!stricmp(f->name, "bboxCenter") || !stricmp(f->name, "bboxSize")) { + gf_list_del_item(n->Fields, f); + gf_free(f); + } + } + } + } + + + for (k=0; kFields); i++) { + f = gf_list_get(n->Fields, i); + //nothing on events + if (!strcmp(f->type, "eventIn")) continue; + if (!strcmp(f->type, "eventOut")) continue; + if (!strcmp(f->def, "")) continue; + if (strstr(f->familly, "Node")) continue; + n->hasDefault = 1; + } + } +} + + +void WriteNodeDump(FILE *f, X3DNode *n) +{ + X3DField *bf; + u32 i; + + fprintf(f, "static const char *%s_FieldName[] = {\n", n->name); + for (i=0; iFields); i++) { + bf = gf_list_get(n->Fields, i); + if (!i) { + fprintf(f, " \"%s\"", bf->name); + } else { + fprintf(f, ", \"%s\"", bf->name); + } + } + fprintf(f, "\n};\n\n"); +} + + +void parse_profile(GF_List *nodes, FILE *prof) +{ + char sLine[2000]; + X3DNode *n; + Bool found; + u32 i; + + while (!feof(prof)) { + fgets(sLine, 2000, prof); + //skip comment and empty lines + if (sLine[0] == '#') continue; + if (sLine[0] == '\n') continue; + if (strstr(sLine, "Proximity")) + found = 0; + found = 1; + while (found) { + switch (sLine[strlen(sLine)-1]) { + case '\n': + case '\r': + case ' ': + sLine[strlen(sLine)-1] = 0; + break; + default: + found = 0; + break; + } + } + + if (0) { + printf("Warning: cannot disable node %s (required in all BIFS profiles)\n", sLine); + } else { + found = 0; + for (i=0; iname, sLine)) { + n->skip_impl = 1; + found = 1; + break; + } + } + if (!found) printf("cannot disable %s: node not found\n", sLine); + } + } +} + +int main (int argc, char **argv) +{ + FILE *nodes, *pf; + GF_List *XNodes, *NDTs; + X3DNode *n; + X3DField *bf; + u32 nb_nodes, nb_imp; + + nodes = gf_fopen("templates_X3D.txt", "rt"); + if (!nodes) { + fprintf(stdout, "cannot open \"templates_X3D.txt\" - aborting\n"); + return 0; + } + + XNodes = gf_list_new(); + NDTs = gf_list_new(); + //all nodes are in the same list but we keep version info + ParseTemplateFile(nodes, XNodes, NDTs); + gf_fclose(nodes); + + if (argc>1) { + pf = gf_fopen(argv[1], "rt"); + if (!pf) fprintf(stdout, "Cannot open profile file %s\n", argv[1]); + else { + parse_profile(XNodes, pf); + gf_fclose(pf); + } + } + + //write the nodes def + WriteNodesFile(XNodes, NDTs); + + nodes = BeginFile(1); + + //write all nodes init stuff + WriteNodeCode(XNodes, nodes); + + WriteNDT(nodes, XNodes, NDTs); + fprintf(nodes, "#endif /*GPAC_DISABLE_X3D*/\n\n"); + + EndFile(nodes, 1); + + //free NDTs + while (gf_list_count(NDTs)) { + char *tmp = gf_list_get(NDTs, 0); + gf_free(tmp); + gf_list_rem(NDTs, 0); + } + gf_list_del(NDTs); + + nb_nodes = gf_list_count(XNodes); + nb_imp = 0; + //free nodes + while (gf_list_count(XNodes)) { + n = gf_list_get(XNodes, 0); + if (!n->skip_impl) nb_imp++; + gf_list_rem(XNodes, 0); + while (gf_list_count(n->NDT)) { + char *tmp = gf_list_get(n->NDT, 0); + gf_free(tmp); + gf_list_rem(n->NDT, 0); + } + gf_list_del(n->NDT); + while (gf_list_count(n->Fields)) { + bf = gf_list_get(n->Fields, 0); + gf_free(bf); + gf_list_rem(n->Fields, 0); + } + gf_list_del(n->Fields); + gf_free(n); + } + gf_list_del(XNodes); + + fprintf(stdout, "Generation done: %d nodes implemented (%d nodes total)\n", nb_imp, nb_nodes); + return 0; +} + diff --git a/applications/generators/X3D/skip.txt b/applications/generators/X3D/skip.txt new file mode 100644 index 0000000..62cae25 --- /dev/null +++ b/applications/generators/X3D/skip.txt @@ -0,0 +1,130 @@ +#X3D defined nodes + +#Anchor +#Appearance +#Arc2D +#ArcClose2D +#AudioClip +#Background +#Billboard +#BooleanFilter +#BooleanSequencer +#BooleanToggle +#BooleanTrigger +#Box +#Circle2D +#Collision +#Color +#ColorInterpolator +#ColorRGBA +#Cone +#Contour2D +#ContourPolyline2D +#Coordinate +#CoordinateDouble +#Coordinate2D +#CoordinateInterpolator +#CoordinateInterpolator2D +#Cylinder +#CylinderSensor +#DirectionalLight +#Disk2D +#ElevationGrid +EspduTransform +#Extrusion +#FillProperties +#Fog +#FontStyle +GeoCoordinate +GeoElevationGrid +GeoLocation +GeoLOD +GeoMetadata +GeoOrigin +GeoPositionInterpolator +GeoTouchSensor +GeoViewpoint +#Group +HAnimDisplacer +HAnimHumanoid +HAnimJoint +HAnimSegment +HAnimSite +#ImageTexture +#IndexedFaceSet +#IndexedLineSet +#IndexedTriangleFanSet +#IndexedTriangleSet +#IndexedTriangleStripSet +#Inline +#IntegerSequencer +#IntegerTrigger +#KeySensor +#LineProperties +#LineSet +LoadSensor +#LOD +#Material +#MetadataDouble +#MetadataFloat +#MetadataInteger +#MetadataSet +#MetadataString +#MovieTexture +#MultiTexture +#MultiTextureCoordinate +#MultiTextureTransform +#NavigationInfo +#Normal +#NormalInterpolator +NurbsCurve +NurbsCurve2D +NurbsOrientationInterpolator +NurbsPatchSurface +NurbsPositionInterpolator +NurbsSet +NurbsSurfaceInterpolator +NurbsSweptSurface +NurbsSwungSurface +NurbsTextureCoordinate +NurbsTrimmedSurface +#OrientationInterpolator +#PixelTexture +#PlaneSensor +#PointLight +#PointSet +#Polyline2D +#Polypoint2D +#PositionInterpolator +#PositionInterpolator2D +#ProximitySensor +ReceiverPdu +#Rectangle2D +#ScalarInterpolator +#Script +#Shape +SignalPdu +#Sound +#Sphere +#SphereSensor +#SpotLight +#StaticGroup +#StringSensor +#Switch +#Text +#TextureBackground +#TextureCoordinate +#TextureCoordinateGenerator +#TextureTransform +#TimeSensor +#TimeTrigger +#TouchSensor +#Transform +TransmitterPdu +#TriangleFanSet +#TriangleSet +#TriangleSet2D +#TriangleStripSet +#Viewpoint +#VisibilitySensor +#WorldInfo diff --git a/applications/generators/X3D/templates_X3D.txt b/applications/generators/X3D/templates_X3D.txt new file mode 100644 index 0000000..5f235da --- /dev/null +++ b/applications/generators/X3D/templates_X3D.txt @@ -0,0 +1,1644 @@ +# GPAC X3D template file +# X3D nodes in GPAC are designed so that they match their MPEG-4 counterparts in order to perform type casting, whenever possible ('#X3D extensions' signaled). +# ommented fields are fields where X3D spec, DTD and XSD disagree +# + +#NOT AN MPEG4 extensions because of activate eventIn in mpeg4 +PROTO Anchor [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFString description "" +exposedField MFString parameter [] +exposedField MFURL url [] +exposedField SFMetadataNode metadata NULL +]{ +} + +PROTO Appearance [ #%NDT=SFWorldNode,SFAppearanceNode +exposedField SFMaterialNode material NULL +exposedField SFTextureNode texture NULL +exposedField SFTextureTransformNode textureTransform NULL +#X3D extensions +exposedField SFFillPropertiesNode fillProperties NULL +exposedField SFX3DLinePropertiesNode lineProperties NULL +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Arc2D [ #%NDT=SFWorldNode,SFGeometryNode +field SFFloat endAngle 1.5707963 +field SFFloat radius 1 +field SFFloat startAngle 0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO ArcClose2D [ #%NDT=SFWorldNode,SFGeometryNode +field SFString closureType "PIE" +field SFFloat endAngle 1.5707963 +field SFFloat radius 1 +field SFFloat startAngle 0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO AudioClip [ #%NDT=SFWorldNode,SFAudioNode,SFStreamingNode +exposedField SFString description "" +exposedField SFBool loop FALSE +exposedField SFFloat pitch 1.0 +exposedField SFTime startTime 0 +exposedField SFTime stopTime 0 +exposedField MFURL url [] +eventOut SFTime duration_changed +eventOut SFBool isActive +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFTime pauseTime 0 +exposedField SFTime resumeTime 0 +eventOut SFTime elapsedTime +eventOut SFBool isPaused +] { +} + +PROTO Background [ #%NDT=SFWorldNode,SF3DNode,SFBackground3DNode +eventIn SFBool set_bind +exposedField MFFloat groundAngle [] +exposedField MFColor groundColor [] +exposedField MFURL backUrl [] +exposedField MFURL bottomUrl [] +exposedField MFURL frontUrl [] +exposedField MFURL leftUrl [] +exposedField MFURL rightUrl [] +exposedField MFURL topUrl [] +exposedField MFFloat skyAngle [] +exposedField MFColor skyColor [ 0 0 0 ] +eventOut SFBool isBound +#X3D extensions +exposedField SFMetadataNode metadata NULL +eventOut SFTime bindTime +] { +} + +PROTO Billboard [ #%NDT=SFWorldNode,SF3DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFVec3f axisOfRotation 0 1 0 +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO BooleanFilter [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFBool set_boolean +eventOut SFBool inputFalse +eventOut SFBool inputNegate +eventOut SFBool inputTrue +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO BooleanSequencer [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFBool next +eventIn SFBool previous +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFBool keyValue [] +eventOut SFBool value_changed +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO BooleanToggle [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFBool set_boolean +exposedField SFBool toggle FALSE +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO BooleanTrigger [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFTime set_triggerTime +eventOut SFBool triggerTrue +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Box [ #%NDT=SFWorldNode,SFGeometryNode +field SFVec3f size 2 2 2 +#X3D extensions +exposedField SFMetadataNode metadata NULL +#field SFBool solid TRUE +] { +} + +PROTO Circle2D [ #%NDT=SFWorldNode,SFGeometryNode +exposedField SFFloat radius 1 +exposedField SFMetadataNode metadata NULL +] { +} + +#note the MPEG-4 version uses "collide" instead of 'enabled" +PROTO Collision [ #%NDT=SFWorldNode,SF3DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFBool enabled TRUE +field SF3DNode proxy NULL +eventOut SFTime collideTime +eventOut SFBool isActive +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Color [ #%NDT=SFWorldNode,SFColorNode +exposedField MFColor color [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO ColorInterpolator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFColor keyValue [] +eventOut SFColor value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO ColorRGBA [ #%NDT=SFWorldNode,SFColorNode +exposedField MFColorRGBA color [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Cone [ #%NDT=SFWorldNode,SFGeometryNode +field SFFloat bottomRadius 1 +field SFFloat height 2 +field SFBool side TRUE +field SFBool bottom TRUE +#X3D extensions +exposedField SFMetadataNode metadata NULL +#field SFBool solid TRUE +] { +} + +PROTO Contour2D [#%NDT=SFWorldNode,SFNurbsControlCurveNode +eventIn MFNurbsControlCurveNode addChildren +eventIn MFNurbsControlCurveNode removeChildren +exposedField MFNurbsControlCurveNode children [] +exposedField SFMetadataNode metadata NULL +]{ +} + +PROTO ContourPolyline2D #%NDT=SFWorldNode,SFNurbsControlCurveNode + exposedField MFVec2f point [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Coordinate [ #%NDT=SFWorldNode,SFCoordinateNode +exposedField MFVec3f point [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} +PROTO CoordinateDouble [ #%NDT=SFWorldNode,SFCoordinateNode +exposedField MFVec3d point [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Coordinate2D [ #%NDT=SFWorldNode,SFCoordinate2DNode +exposedField MFVec2f point [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO CoordinateInterpolator [ #%NDT=SFWorldNode,SF3DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFVec3f keyValue [] +eventOut MFVec3f value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO CoordinateInterpolator2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFVec2f keyValue [] +eventOut MFVec2f value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Cylinder [ #%NDT=SFWorldNode,SFGeometryNode +field SFBool bottom TRUE +field SFFloat height 2 +field SFFloat radius 1 +field SFBool side TRUE +field SFBool top TRUE +#X3D extensions +exposedField SFMetadataNode metadata NULL +#field SFBool solid TRUE +] { +} + +PROTO CylinderSensor [ #%NDT=SFWorldNode,SF3DNode +exposedField SFBool autoOffset TRUE +exposedField SFFloat diskAngle 0.2617 +exposedField SFBool enabled TRUE +exposedField SFFloat maxAngle -1 +exposedField SFFloat minAngle 0 +exposedField SFFloat offset 0 +eventOut SFBool isActive +eventOut SFRotation rotation_changed +eventOut SFVec3f trackPoint_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFString description "" +eventOut SFBool isOver +] { +} + +PROTO DirectionalLight [ #%NDT=SFWorldNode,SF3DNode +exposedField SFFloat ambientIntensity 0 +exposedField SFColor color 1 1 1 +exposedField SFVec3f direction 0 0 -1 +exposedField SFFloat intensity 1 +exposedField SFBool on TRUE +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Disk2D [#%NDT=SFWorldNode,SFGeometryNode +field SFFloat innerRadius 0 +field SFFloat outerRadius 1 +#field SFBool solid FALSE +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO ElevationGrid [ #%NDT=SFWorldNode,SFGeometryNode +eventIn MFFloat set_height +exposedField SFColorNode color NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field MFFloat height [] +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFFloat creaseAngle 0.0 +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field SFInt32 xDimension 0 +field SFFloat xSpacing 1.0 +field SFInt32 zDimension 0 +field SFFloat zSpacing 1.0 +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO EspduTransform [#%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +eventIn SFFloat set_articulationParameterValue0 +eventIn SFFloat set_articulationParameterValue1 +eventIn SFFloat set_articulationParameterValue2 +eventIn SFFloat set_articulationParameterValue3 +eventIn SFFloat set_articulationParameterValue4 +eventIn SFFloat set_articulationParameterValue5 +eventIn SFFloat set_articulationParameterValue6 +eventIn SFFloat set_articulationParameterValue7 +exposedField SFString address "localhost" +exposedField SFInt32 applicationID 1 +exposedField SFInt32 articulationParameterCount 0 +exposedField MFInt32 articulationParameterDesignatorArray [] +exposedField MFInt32 articulationParameterChangeIndicatorArray [] +exposedField MFInt32 articulationParameterIdPartAttachedToArray [] +exposedField MFInt32 articulationParameterTypeArray [] +exposedField MFFloat articulationParameterArray [] +exposedField SFVec3f center 0 0 0 +exposedField MF3DNode children [] +exposedField SFInt32 collisionType 0 +exposedField SFInt32 deadReckoning 0 +exposedField SFVec3f detonationLocation 0 0 0 +exposedField SFVec3f detonationRelativeLocation 0 0 0 +exposedField SFInt32 detonationResult 0 +exposedField SFInt32 entityCategory 0 +exposedField SFInt32 entityCountry 0 +exposedField SFInt32 entityDomain 0 +exposedField SFInt32 entityExtra 0 +exposedField SFInt32 entityID 0 +exposedField SFInt32 entityKind 0 +exposedField SFInt32 entitySpecific 0 +exposedField SFInt32 entitySubCategory 0 +exposedField SFInt32 eventApplicationID 1 +exposedField SFInt32 eventEntityID 0 +exposedField SFInt32 eventNumber 0 +exposedField SFInt32 eventSiteID 0 +exposedField SFBool fired1 FALSE +exposedField SFBool fired2 FALSE +exposedField SFInt32 fireMissionIndex 0 +exposedField SFFloat firingRange 0.0 +exposedField SFInt32 firingRate 0 +exposedField SFInt32 forceID 0 +exposedField SFInt32 fuse 0 +exposedField SFVec3f linearVelocity 0 0 0 +exposedField SFVec3f linearAcceleration 0 0 0 +exposedField SFString marking "" +exposedField SFString multicastRelayHost "" +exposedField SFInt32 multicastRelayPort 0 +exposedField SFInt32 munitionApplicationID 1 +exposedField SFVec3f munitionEndPoint 0 0 0 +exposedField SFInt32 munitionEntityID 0 +exposedField SFInt32 munitionQuantity 0 +exposedField SFInt32 munitionSiteID 0 +exposedField SFVec3f munitionStartPoint 0 0 0 +exposedField SFString networkMode "standAlone" +exposedField SFInt32 port 0 +exposedField SFTime readInterval 0.1 +exposedField SFRotation rotation 0 0 1 0 +exposedField SFVec3f scale 1 1 1 +exposedField SFRotation scaleOrientation 0 0 1 0 +exposedField SFInt32 siteID 0 +exposedField SFVec3f translation 0 0 0 +exposedField SFInt32 warhead 0 +exposedField SFTime writeInterval 1.0 +field SFBool rtpHeaderExpected FALSE +eventOut SFFloat articulationParameterValue0_changed 0.0 +eventOut SFFloat articulationParameterValue1_changed 0.0 +eventOut SFFloat articulationParameterValue2_changed 0.0 +eventOut SFFloat articulationParameterValue3_changed 0.0 +eventOut SFFloat articulationParameterValue4_changed 0.0 +eventOut SFFloat articulationParameterValue5_changed 0.0 +eventOut SFFloat articulationParameterValue6_changed 0.0 +eventOut SFFloat articulationParameterValue7_changed 0.0 +eventOut SFTime collideTime 0 +eventOut SFTime detonateTime 0 +eventOut SFTime firedTime 0 +eventOut SFBool isActive FALSE +eventOut SFBool isCollided FALSE +eventOut SFBool isDetonated FALSE +eventOut SFBool isNetworkReader FALSE +eventOut SFBool isNetworkWriter FALSE +eventOut SFBool isRtpHeaderHeard FALSE +eventOut SFBool isStandAlone FALSE +eventOut SFTime timestamp 0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Extrusion [ #%NDT=SFWorldNode,SFGeometryNode +eventIn MFVec2f set_crossSection +eventIn MFRotation set_orientation +eventIn MFVec2f set_scale +eventIn MFVec3f set_spine +field SFBool beginCap TRUE +field SFBool ccw TRUE +field SFBool convex TRUE +field SFFloat creaseAngle 0.0 +field MFVec2f crossSection [ 1 1, 1 -1, -1 -1, -1 1, 1 1 ] +field SFBool endCap TRUE +field MFRotation orientation [0 0 1 0] +field MFVec2f scale [1 1] +field SFBool solid TRUE +field MFVec3f spine [ 0 0 0, 0 1 0 ] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO FillProperties [ #%NDT=SFWorldNode,SFFillPropertiesNode +exposedField SFBool filled TRUE +exposedField SFColor hatchColor 1 1 1 +exposedField SFBool hatched TRUE +exposedField SFInt32 hatchStyle 1 +] { +} + +PROTO Fog [ #%NDT=SFWorldNode,SF3DNode,SFFogNode +exposedField SFColor color 1 1 1 +exposedField SFString fogType "LINEAR" +exposedField SFFloat visibilityRange 0 +eventIn SFBool set_bind +eventOut SFBool isBound +#X3D extensions +exposedField SFMetadataNode metadata NULL +eventOut SFTime bindTime +] { +} + + +PROTO FontStyle [ #%NDT=SFWorldNode,SFFontStyleNode +exposedField MFString family ["SERIF"] +exposedField SFBool horizontal TRUE +exposedField MFString justify ["BEGIN"] +exposedField SFString language "" +exposedField SFBool leftToRight TRUE +exposedField SFFloat size 1.0 +exposedField SFFloat spacing 1.0 +exposedField SFString style "PLAIN" +exposedField SFBool topToBottom TRUE +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO GeoCoordinate [#%NDT=SFWorldNode,SFCoordinateNode +exposedField MFVec3d point [] +field SFGeoOriginNode geoOrigin NULL +field MFString geoSystem ["GD", "WE"] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO GeoElevationGrid [#%NDT=SFWorldNode,SFGeometryNode +eventIn MFDouble set_height +exposedField SFColorNode color NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +exposedField SFFloat yScale 1.0 +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFFloat creaseAngle 0.0 +field SFString geoGridOrigin "0 0 0" +field SFGeoOriginNode geoOrigin NULL +field MFString geoSystem ["GD", "WE"] +field MFDouble height [] +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field SFInt32 xDimension 0 +field SFDouble xSpacing 1.0 +field SFInt32 zDimension 0 +field SFDouble zSpacing 1.0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO GeoLocation [#%NDT=SFWorldNode,SF3DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFVec3d geoCoords 0 0 0 +field SFGeoOriginNode geoOrigin NULL +field MFString geoSystem ["GD", "WE"] +exposedField SFMetadataNode metadata NULL +]{ +} + +#addChildren and removeChildren are commented, it looks like a bug in X3D spec +PROTO GeoLOD [#%NDT=SFWorldNode,SF3DNode +# eventIn MF3DNode addChildren +# eventIn MF3DNode removeChildren +field SFVec3d center 0 0 0 +field MFURL child1Url [] +field MFURL child2Url [] +field MFURL child3Url [] +field MFURL child4Url [] +field SFGeoOriginNode geoOrigin NULL +field MFString geoSystem ["GD","WE"] +field SFFloat range 10 +field MFURL rootUrl [] +field MF3DNode rootNode [] +eventOut MF3DNode children +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO GeoMetadata [#%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField MF3DNode data [] +exposedField MFString summary [] +exposedField MFURL url [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO GeoOrigin [%#NDT=SFGeoOriginNode +exposedField SFVec3d geoCoords 0 0 0 +exposedField MFString geoSystem ["GD","WE"] +field SFBool rotateYUp FALSE +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO GeoPositionInterpolator [ #%NDT=SFWorldNode,SF3DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFVec3d keyValue [] +field SFGeoOriginNode geoOrigin NULL +field MFString geoSystem ["GD","WE"] +eventOut SFVec3d geovalue_changed +eventOut SFVec3f value_changed +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO GeoTouchSensor [ #%NDT=SFWorldNode,SF2DNode,SF3DNode +exposedField SFBool enabled TRUE +field SFGeoOriginNode geoOrigin NULL +field MFString geoSystem ["GD","WE"] +eventOut SFVec3f hitNormal_changed +eventOut SFVec3f hitPoint_changed +eventOut SFVec2f hitTexCoord_changed +eventOut SFVec3d hitGeoCoord_changed +eventOut SFBool isActive +eventOut SFBool isOver +eventOut SFTime touchTime +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO GeoViewpoint [#%NDT=SFWorldNode,SF3DNode,SFViewpointNode +eventIn SFBool set_bind +eventIn SFString set_orientation +eventIn SFString set_position +exposedField SFString description "" +exposedField SFFloat fieldOfView 0.785398 +exposedField SFBool headlight TRUE +exposedField SFBool jump TRUE +exposedField MFString navType ["EXAMINE","ANY"] +eventOut SFTime bindTime +eventOut SFBool isBound +field SFGeoOriginNode geoOrigin NULL +field MFString geoSystem ["GD","WE"] +field SFRotation orientation 0 0 1 0 +field SFVec3d position 0 0 100000 +field SFFloat speedFactor 1.0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Group [ #%NDT=SFWorldNode,SFTopNode,SF3DNode,SF2DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO HAnimDisplacer [#%NDT=SFWorldNode,SFHAnimDisplacerNode +exposedField MFInt32 coordIndex [] +exposedField MFVec3f displacements [] +exposedField SFString name "" +exposedField SFFloat weight 0.0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO HAnimHumanoid [#%NDT=SFWorldNode,SF3DNode +exposedField SFVec3f center 0 0 0 +exposedField MFString info [] +exposedField MFHAnimNode joints [] +exposedField SFString name "" +exposedField SFRotation rotation 0 0 1 0 +exposedField SFVec3f scale 1 1 1 +exposedField SFRotation scaleOrientation 0 0 1 0 +exposedField MFHAnimNode segments [] +exposedField MFHAnimNode sites [] +exposedField MFHAnimNode skeleton [] +exposedField MF3DNode skin [] +exposedField SFCoordinateNode skinCoord NULL +exposedField SFNormalNode skinNormal NULL +exposedField SFVec3f translation 0 0 0 +exposedField SFString version "" +exposedField MFViewpointNode viewpoints [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO HAnimJoint [#%NDT=SFWorldNode,SFHAnimNode +eventIn MFHAnimNode addChildren +eventIn MFHAnimNode removeChildren +exposedField MFHAnimNode children [] +exposedField SFVec3f center 0 0 0 +exposedField MFHAnimDisplacerNode displacers [] +exposedField SFRotation limitOrientation 0 0 1 0 +exposedField MFFloat llimit [] +exposedField SFString name "" +exposedField SFRotation rotation 0 0 1 0 +exposedField SFVec3f scale 1 1 1 +exposedField SFRotation scaleOrientation 0 0 1 0 +exposedField MFInt32 skinCoordIndex [] +exposedField MFFloat skinCoordWeight [] +exposedField MFFloat stiffness [0 0 0] +exposedField SFVec3f translation 0 0 0 +exposedField MFFloat ulimit [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO HAnimSegment [#%NDT=SFWorldNode,SFHAnimNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFVec3f centerOfMass 0 0 0 +exposedField SFCoordinateNode coord NULL +exposedField MFHAnimDisplacerNode displacers [] +exposedField SFFloat mass 0 +exposedField MFFloat momentsOfInertia [0 0 0 0 0 0 0 0 0] +exposedField SFString name "" +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO HAnimSite [#%NDT=SFWorldNode,SFHAnimNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFVec3f center 0 0 0 +exposedField SFString name "" +exposedField SFRotation rotation 0 0 1 0 +exposedField SFVec3f scale 1 1 1 +exposedField SFRotation scaleOrientation 0 0 1 0 +exposedField SFVec3f translation 0 0 0 +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO ImageTexture [ #%NDT=SFWorldNode,SFTextureNode +exposedField MFURL url [] +field SFBool repeatS TRUE +field SFBool repeatT TRUE +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO IndexedFaceSet [ #%NDT=SFWorldNode,SFGeometryNode +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +eventIn MFInt32 set_normalIndex +eventIn MFInt32 set_texCoordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field MFInt32 colorIndex [] +field SFBool colorPerVertex TRUE +field SFBool convex TRUE +field MFInt32 coordIndex [] +field SFFloat creaseAngle 0.0 +field MFInt32 normalIndex [] +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field MFInt32 texCoordIndex [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO IndexedLineSet [ #%NDT=SFWorldNode,SFGeometryNode +eventIn MFInt32 set_colorIndex +eventIn MFInt32 set_coordIndex +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +field MFInt32 colorIndex [] +field SFBool colorPerVertex TRUE +field MFInt32 coordIndex [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO IndexedTriangleFanSet [ #%NDT=SFWorldNode,SFGeometryNode +eventIn MFInt32 set_index +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field MFInt32 index [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO IndexedTriangleSet [ #%NDT=SFWorldNode,SFGeometryNode +eventIn MFInt32 set_index +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field MFInt32 index [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO IndexedTriangleStripSet [ #%NDT=SFWorldNode,SFGeometryNode +eventIn MFInt32 set_index +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFFloat creaseAngle 0 +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +field MFInt32 index [] +exposedField SFMetadataNode metadata NULL +] { +} + + + +PROTO Inline [ #%NDT=SFWorldNode,SF3DNode,SFStreamingNode,SF2DNode +exposedField MFURL url [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFBool load TRUE +] { +} + + +PROTO IntegerSequencer [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFBool next +eventIn SFBool previous +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFInt32 keyValue [] +eventOut SFInt32 value_changed +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO IntegerTrigger [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFBool set_boolean +exposedField SFInt32 integerKey -1 +eventOut SFInt32 triggerValue +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO KeySensor [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField SFBool enabled TRUE +eventOut SFInt32 actionKeyPress +eventOut SFInt32 actionKeyRelease +eventOut SFBool altKey +eventOut SFBool controlKey +eventOut SFBool isActive +eventOut SFString keyPress +eventOut SFString keyRelease +eventOut SFBool shiftKey +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO LineProperties [ #%NDT=SFWorldNode,SFX3DLinePropertiesNode +exposedField SFBool applied TRUE +exposedField SFInt32 linetype 1 +exposedField SFFloat linewidthScaleFactor 0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO LineSet [ #%NDT=SFWorldNode,SFGeometryNode +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField MFInt32 vertexCount [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO LoadSensor [ #%NDT=SFWorldNode,SFStreamingNode +exposedField SFBool enabled TRUE +exposedField SFTime timeOut 0 +exposedField MFStreamingNode watchList [] +eventOut SFBool isActive +eventOut SFBool isLoaded +eventOut SFTime loadTime +eventOut SFFloat progress +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO LOD [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +field SFVec3f center 0 0 0 +field MFFloat range [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Material [ #%NDT=SFWorldNode,SFMaterialNode +exposedField SFFloat ambientIntensity 0.2 +exposedField SFColor diffuseColor 0.8 0.8 0.8 +exposedField SFColor emissiveColor 0 0 0 +exposedField SFFloat shininess 0.2 +exposedField SFColor specularColor 0 0 0 +exposedField SFFloat transparency 0 +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + + + +PROTO MetadataDouble [ #%NDT=SFWorldNode,SFMetadataNode +exposedField SFString name "" +exposedField SFString reference "" +exposedField MFDouble value [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO MetadataFloat[ #%NDT=SFWorldNode,SFMetadataNode +exposedField SFString name "" +exposedField SFString reference "" +exposedField MFFloat value [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO MetadataInteger [ #%NDT=SFWorldNode,SFMetadataNode +exposedField SFString name "" +exposedField SFString reference "" +exposedField MFInt32 value [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO MetadataSet [ #%NDT=SFWorldNode,SFMetadataNode +exposedField SFString name "" +exposedField SFString reference "" +exposedField MFMetadataNode value [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO MetadataString [ #%NDT=SFWorldNode,SFMetadataNode +exposedField SFString name "" +exposedField SFString reference "" +exposedField MFString value [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO MovieTexture [ #%NDT=SFWorldNode,SFTextureNode,SFStreamingNode +exposedField SFBool loop FALSE +exposedField SFFloat speed 1.0 +exposedField SFTime startTime 0 +exposedField SFTime stopTime 0 +exposedField MFURL url [] +field SFBool repeatS TRUE +field SFBool repeatT TRUE +eventOut SFTime duration_changed +eventOut SFBool isActive +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFTime resumeTime 0 +exposedField SFTime pauseTime 0 +eventOut SFTime elapsedTime +eventOut SFBool isPaused +] { +} + +PROTO MultiTexture [ #%NDT=SFWorldNode,SFTextureNode +exposedField SFFloat alpha 1 +exposedField SFColor color 1 1 1 +exposedField MFString function [] +exposedField MFString mode [] +exposedField MFString source [] +exposedField MFTextureNode texture [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO MultiTextureCoordinate [ #%NDT=SFWorldNode,SFTextureCoordinateNode +MultiTextureCoordinate MFTextureCoordinateNode texCoord NULL +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO MultiTextureTransform [ #%NDT=SFWorldNode,SFTextureTransformNode +exposedField MFTextureTransformNode textureTransform [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NavigationInfo [ #%NDT=SFWorldNode,SF3DNode,SFNavigationInfoNode +eventIn SFBool set_bind +exposedField MFFloat avatarSize [0.25, 1.6, 0.75] +exposedField SFBool headlight TRUE +exposedField SFFloat speed 1.0 +exposedField MFString type ["WALK", "ANY"] +exposedField SFFloat visibilityLimit 0.0 +eventOut SFBool isBound +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField MFString transitionType ["WALK", "ANY"] +eventOut SFTime bindTime +]{ +} + +PROTO Normal [ #%NDT=SFWorldNode,SFNormalNode +exposedField MFVec3f vector [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NormalInterpolator [ #%NDT=SFWorldNode,SF3DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFVec3f keyValue [] +eventOut MFVec3f value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO NurbsCurve [ #%NDT=SFWorldNode,SFGeometryNode,SFNurbsCurveNode +exposedField MFVec3f controlPoint [] +exposedField SFInt32 tessellation 0 +exposedField MFDouble weight [] +field SFBool closed FALSE +field MFFloat knot [] +field SFInt32 order 3 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsCurve2D [ #%NDT=SFWorldNode,SFNurbsControlCurveNode +exposedField MFVec2f controlPoint [] +exposedField SFInt32 tessellation 0 +exposedField MFFloat weight [] +field MFFloat knot [] +field SFInt32 order 3 +field SFBool closed FALSE +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsOrientationInterpolator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFFloat set_fraction +exposedField SFCoordinateNode controlPoints NULL +exposedField MFDouble knot [] +exposedField SFInt32 order 3 +exposedField MFDouble weight [] +eventOut SFRotation value_changed +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsPatchSurface [ #%NDT=SFWorldNode,SFGeometryNode,SFNurbsSurfaceNode +exposedField SFCoordinateNode controlPoint NULL +exposedField SFTextureCoordinateNode texCoord NULL +exposedField SFInt32 uTessellation 0 +exposedField SFInt32 vTessellation 0 +exposedField MFDouble weight [] +field SFBool solid TRUE +field SFBool uClosed FALSE +field SFInt32 uDimension 0 +field MFDouble uKnot [] +field SFInt32 uOrder 3 +field SFBool vClosed FALSE +field SFInt32 vDimension 0 +field MFDouble vKnot [] +field SFInt32 vOrder 3 +exposedField SFMetadataNode metadata NULL +] { + } + +PROTO NurbsPositionInterpolator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFFloat set_fraction +exposedField SFCoordinateNode controlPoints NULL +exposedField MFDouble knot [] +exposedField SFInt32 order 3 +exposedField MFDouble weight [] +eventOut SFVec3f value_changed +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsSet [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn MFNurbsSurfaceNode addGeometry +eventIn MFNurbsSurfaceNode removeGeometry +exposedField MFNurbsSurfaceNode geometry [] +exposedField SFFloat tessellationScale 1.0 +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO NurbsSurfaceInterpolator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFVec2f set_fraction +exposedField SFCoordinateNode controlPoints NULL +exposedField MFDouble weight [] +eventOut SFVec3f position_changed +eventOut SFVec3f normal_changed +field SFInt32 uDimension 0 +field MFDouble uKnot [] +field SFInt32 uOrder 3 +field SFInt32 vDimension 0 +field MFDouble vKnot [] +field SFInt32 vOrder 3 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsSweptSurface [ #%NDT=SFWorldNode,SFGeometryNode,SFNurbsSurfaceNode +exposedField SFNurbsControlCurveNode crossSectionCurve NULL +exposedField SFNurbsCurveNode trajectoryCurve NULL +field SFBool ccw TRUE +field SFBool solid TRUE +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsSwungSurface [ #%NDT=SFWorldNode,SFGeometryNode,SFNurbsSurfaceNode +exposedField SFNurbsControlCurveNode profileCurve NULL +exposedField SFNurbsControlCurveNode trajectoryCurve NULL +field SFBool ccw TRUE +field SFBool solid TRUE +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsTextureCoordinate [ #%NDT=SFWorldNode,SFTextureCoordinateNode +exposedField MFVec2f controlPoint [] +exposedField MFFloat weight [] +field SFInt32 uDimension 0 +field MFDouble uKnot [] +field SFInt32 uOrder 3 +field SFInt32 vDimension 0 +field MFDouble vKnot [] +field SFInt32 vOrder 3 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO NurbsTrimmedSurface [ #%NDT=SFWorldNode,SFGeometryNode,SFNurbsSurfaceNode +eventIn MFNurbsControlCurveNode addTrimmingContour +eventIn MFNurbsControlCurveNode removeTrimmingContour +exposedField MFNurbsControlCurveNode trimmingContour [] +exposedField SFCoordinateNode controlPoint NULL +exposedField SFTextureCoordinateNode texCoord NULL +exposedField SFInt32 uTessellation 0 +exposedField SFInt32 vTessellation 0 +exposedField MFDouble weight [] +field SFBool solid TRUE +field SFBool uClosed FALSE +field SFInt32 uDimension 0 +field MFDouble uKnot [] +field SFInt32 uOrder 3 +field SFBool vClosed FALSE +field SFInt32 vDimension 0 +field MFDouble vKnot [] +field SFInt32 vOrder 3 +exposedField SFMetadataNode metadata NULL +] { +} + + + +PROTO OrientationInterpolator [ #%NDT=SFWorldNode,SF3DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFRotation keyValue [] +eventOut SFRotation value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO PixelTexture [ #%NDT=SFWorldNode,SFTextureNode +exposedField SFImage image 0 0 0 +field SFBool repeatS TRUE +field SFBool repeatT TRUE +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO PlaneSensor [ #%NDT=SFWorldNode,SF3DNode +exposedField SFBool autoOffset TRUE +exposedField SFBool enabled TRUE +exposedField SFVec2f maxPosition -1 -1 +exposedField SFVec2f minPosition 0 0 +exposedField SFVec3f offset 0 0 0 +eventOut SFBool isActive +eventOut SFVec3f trackPoint_changed +eventOut SFVec3f translation_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFString description "" +eventOut SFBool isOver +] { +} + +PROTO PointLight [ #%NDT=SFWorldNode,SF3DNode +exposedField SFFloat ambientIntensity 0 +exposedField SFVec3f attenuation 1 0 0 +exposedField SFColor color 1 1 1 +exposedField SFFloat intensity 1 +exposedField SFVec3f location 0 0 0 +exposedField SFBool on TRUE +exposedField SFFloat radius 100 +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO PointSet [ #%NDT=SFWorldNode,SFGeometryNode +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Polyline2D [#%NDT=SFWorldNode,SFGeometryNode +exposedField MFVec2f lineSegments [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Polypoint2D [#%NDT=SFWorldNode,SFGeometryNode +exposedField MFVec2f point [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO PositionInterpolator [ #%NDT=SFWorldNode,SF3DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFVec3f keyValue [] +eventOut SFVec3f value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO PositionInterpolator2D [ #%NDT=SFWorldNode,SF2DNode,SF3DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFVec2f keyValue [] +eventOut SFVec2f value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO ProximitySensor [ #%NDT=SFWorldNode,SF3DNode +exposedField SFVec3f center 0 0 0 +exposedField SFVec3f size 0 0 0 +exposedField SFBool enabled TRUE +eventOut SFBool isActive +eventOut SFVec3f position_changed +eventOut SFRotation orientation_changed +eventOut SFTime enterTime +eventOut SFTime exitTime +#X3D extensions +exposedField SFMetadataNode metadata NULL +eventOut SFVec3f centerOfRotation_changed +] { +} + +PROTO ReceiverPdu [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField SFString address "localhost" +exposedField SFInt32 applicationID 1 +exposedField SFInt32 entityID 0 +exposedField SFString multicastRelayHost "" +exposedField SFInt32 multicastRelayPort 0 +exposedField SFString networkMode "standAlone" +exposedField SFInt32 port 0 +exposedField SFInt32 radioID 0 +exposedField SFFloat readInterval 0.1 +exposedField SFFloat receivedPower 0.0 +exposedField SFInt32 receiverState 0 +exposedField SFBool rtpHeaderExpected +exposedField SFInt32 siteID 0 +exposedField SFInt32 transmitterApplicationID 1 +exposedField SFInt32 transmitterEntityID 0 +exposedField SFInt32 transmitterRadioID 0 +exposedField SFInt32 transmitterSiteID 0 +exposedField SFInt32 whichGeometry 1 +exposedField SFFloat writeInterval 1.0 +eventOut SFBool isActive FALSE +eventOut SFBool isNetworkReader FALSE +eventOut SFBool isNetworkWriter FALSE +eventOut SFBool isRtpHeaderHeard FALSE +eventOut SFBool isStandAlone FALSE +eventOut SFTime timestamp 0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Rectangle2D [ #%NDT=SFWorldNode,SFGeometryNode +field SFVec2f size 2 2 +#X3D extensions +exposedField SFMetadataNode metadata NULL +#exposedField SFBool filled TRUE +]{ +} + +PROTO ScalarInterpolator [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFFloat set_fraction +exposedField MFFloat key [] +exposedField MFFloat keyValue [] +eventOut SFFloat value_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +]{} + +PROTO Script [#%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField MFScript url [] +field SFBool directOutput FALSE +field SFBool mustEvaluate FALSE +#X3D extensions +exposedField SFMetadataNode metadata NULL +]{ +} + +PROTO Shape [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField SFAppearanceNode appearance NULL +exposedField SFGeometryNode geometry NULL +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO SignalPdu [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField SFString address "localhost" +exposedField SFInt32 applicationID 1 +exposedField MFInt32 data [] +exposedField SFInt32 dataLength 0 +exposedField SFInt32 encodingScheme 0 +exposedField SFInt32 entityID 0 +exposedField SFString multicastRelayHost "" +exposedField SFInt32 multicastRelayPort 0 +exposedField SFString networkMode "standAlone" +exposedField SFInt32 port 0 +exposedField SFInt32 radioID 0 +exposedField SFFloat readInterval 0.1 +exposedField SFBool rtpHeaderExpected FALSE +exposedField SFInt32 sampleRate 0 +exposedField SFInt32 samples 0 +exposedField SFInt32 siteID 0 +exposedField SFInt32 tdlType 0 +exposedField SFInt32 whichGeometry 1 +exposedField SFFloat writeInterval 1.0 +eventOut SFBool isActive +eventOut SFBool isNetworkReader +eventOut SFBool isNetworkWriter +eventOut SFBool isRtpHeaderHeard +eventOut SFBool isStandAlone +eventOut SFTime timestamp +exposedField SFMetadataNode metadata NULL +] { +} + + + +PROTO Sound [ #%NDT=SFWorldNode,SF3DNode +exposedField SFVec3f direction 0 0 1 +exposedField SFFloat intensity 1 +exposedField SFVec3f location 0 0 0 +exposedField SFFloat maxBack 10 +exposedField SFFloat maxFront 10 +exposedField SFFloat minBack 1 +exposedField SFFloat minFront 1 +exposedField SFFloat priority 0 +exposedField SFAudioNode source NULL +field SFBool spatialize TRUE +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO Sphere [ #%NDT=SFWorldNode,SFGeometryNode +field SFFloat radius 1 +#X3D extensions +exposedField SFMetadataNode metadata NULL +#field SFBool solid TRUE +] { +} + + +PROTO SphereSensor [ #%NDT=SFWorldNode,SF3DNode +exposedField SFBool autoOffset TRUE +exposedField SFBool enabled TRUE +exposedField SFRotation offset 0 1 0 0 +eventOut SFBool isActive +eventOut SFRotation rotation_changed +eventOut SFVec3f trackPoint_changed +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFString description "" +eventOut SFBool isOver +]{ +} + +PROTO SpotLight [ #%NDT=SFWorldNode,SF3DNode +exposedField SFFloat ambientIntensity 0 +exposedField SFVec3f attenuation 1 0 0 +exposedField SFFloat beamWidth 1.570796 +exposedField SFColor color 1 1 1 +exposedField SFFloat cutOffAngle 0.785398 +exposedField SFVec3f direction 0 0 -1 +exposedField SFFloat intensity 1 +exposedField SFVec3f location 0 0 0 +exposedField SFBool on TRUE +exposedField SFFloat radius 100 +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO StaticGroup [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +field MF3DNode children [] +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO StringSensor [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField SFBool deletionAllowed TRUE +exposedField SFBool enabled TRUE +eventOut SFString enteredText +eventOut SFString finalText +eventOut SFBool isActive +exposedField SFMetadataNode metadata NULL +] { +} + + + +PROTO Switch [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField MF3DNode children [] +exposedField SFInt32 whichChoice -1 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Text [ #%NDT=SFWorldNode,SFGeometryNode +exposedField MFString string [] +exposedField MFFloat length [] +exposedField SFFontStyleNode fontStyle NULL +exposedField SFFloat maxExtent 0.0 +#X3D extensions +exposedField SFMetadataNode metadata NULL +#field SFBool solid FALSE +] { +} + +PROTO TextureBackground [ #%NDT=SFWorldNode,SF3DNode,SFBackground3DNode +eventIn SFBool set_bind +exposedField MFFloat groundAngle [] +exposedField MFColor groundColor [] +exposedField SFTextureNode backTexture NULL +exposedField SFTextureNode bottomTexture NULL +exposedField SFTextureNode frontTexture NULL +exposedField SFTextureNode leftTexture NULL +exposedField SFTextureNode rightTexture NULL +exposedField SFTextureNode topTexture NULL +exposedField MFFloat skyAngle [] +exposedField MFColor skyColor 0 0 0 +exposedField MFFloat transparency 0 +exposedField SFTime bindTime +exposedField SFBool isBound +exposedField SFMetadataNode metadata NULL +] { +} + + + +PROTO TextureCoordinate [ #%NDT=SFWorldNode,SFTextureCoordinateNode +exposedField MFVec2f point [] +#X3D extensions +exposedField SFMetadataNode metadata NULL +]{ +} + +PROTO TextureCoordinateGenerator [ #%NDT=SFWorldNode,SFTextureCoordinateNode +exposedField SFString mode "SPHERE" +TextureCoordinateGenerator MFFloat parameter [] +exposedField SFMetadataNode metadata NULL +] { +} + + + +PROTO TextureTransform [ #%NDT=SFWorldNode,SFTextureTransformNode +exposedField SFVec2f center 0 0 +exposedField SFFloat rotation 0 +exposedField SFVec2f scale 1 1 +exposedField SFVec2f translation 0 0 +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO TimeSensor [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +exposedField SFTime cycleInterval 1 +exposedField SFBool enabled TRUE +exposedField SFBool loop FALSE +exposedField SFTime startTime 0 +exposedField SFTime stopTime 0 +eventOut SFTime cycleTime +eventOut SFFloat fraction_changed +eventOut SFBool isActive +eventOut SFTime time +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFTime pauseTime 0 +exposedField SFTime resumeTime 0 +eventOut SFTime elapsedTime +eventOut SFBool isPaused +] { +} + +PROTO TimeTrigger [ #%NDT=SFWorldNode,SF3DNode,SF2DNode +eventIn SFBool set_boolean +eventOut SFTime triggerTime +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO TouchSensor [ #%NDT=SFWorldNode,SF2DNode,SF3DNode +exposedField SFBool enabled TRUE +eventOut SFVec3f hitNormal_changed +eventOut SFVec3f hitPoint_changed +eventOut SFVec2f hitTexCoord_changed +eventOut SFBool isActive +eventOut SFBool isOver +eventOut SFTime touchTime +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFString description "" +] {} + +PROTO Transform [ #%NDT=SFWorldNode,SF3DNode +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren +exposedField SFVec3f center 0 0 0 +exposedField MF3DNode children [] +exposedField SFRotation rotation 0 0 1 0 +exposedField SFVec3f scale 1 1 1 +exposedField SFRotation scaleOrientation 0 0 1 0 +exposedField SFVec3f translation 0 0 0 +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO TransmitterPdu [ #%NDT=SFWorldNode,SF2DNode,SF3DNode +exposedField SFString address "localhost" +exposedField SFVec3f antennaLocation 0 0 0 +exposedField SFInt32 antennaPatternLength 0 +exposedField SFInt32 antennaPatternType 0 +exposedField SFInt32 applicationID 1 +exposedField SFInt32 cryptoKeyID 0 +exposedField SFInt32 cryptoSystem 0 +exposedField SFInt32 entityID 0 +exposedField SFInt32 frequency 0 +exposedField SFInt32 inputSource 0 +exposedField SFInt32 lengthOfModulationParameters 0 +exposedField SFInt32 modulationTypeDetail 0 +exposedField SFInt32 modulationTypeMajor 0 +exposedField SFInt32 modulationTypeSpreadSpectrum 0 +exposedField SFInt32 modulationTypeSystem 0 +exposedField SFString multicastRelayHost "" +exposedField SFInt32 multicastRelayPort 0 +exposedField SFString networkMode "standAlone" +exposedField SFInt32 port 0 +exposedField SFFloat power 0.0 +exposedField SFInt32 radioEntityTypeCategory 0 +exposedField SFInt32 radioEntityTypeCountry 0 +exposedField SFInt32 radioEntityTypeDomain 0 +exposedField SFInt32 radioEntityTypeKind 0 +exposedField SFInt32 radioEntityTypeNomenclature 0 +exposedField SFInt32 radioEntityTypeNomenclatureVersion 0 +exposedField SFInt32 radioID 0 +exposedField SFFloat readInterval 0.1 +exposedField SFVec3f relativeAntennaLocation 0 0 0 +exposedField SFBool rtpHeaderExpected FALSE +exposedField SFInt32 siteID 0 +exposedField SFFloat transmitFrequencyBandwidth 0.0 +exposedField SFInt32 transmitState 0 +exposedField SFInt32 whichGeometry 1 +exposedField SFFloat writeInterval 1.0 +eventOut SFBool isActive FALSE +eventOut SFBool isNetworkReader FALSE +eventOut SFBool isNetworkWriter FALSE +eventOut SFBool isRtpHeaderHeard FALSE +eventOut SFBool isStandAlone FALSE +eventOut SFTime timestamp 0 +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO TriangleFanSet [ #%NDT=SFWorldNode,SFGeometryNode +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField MFInt32 fanCount [] +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +exposedField SFMetadataNode metadata NULL +] { +} + + +PROTO TriangleSet [ #%NDT=SFWorldNode,SFGeometryNode +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFNormalNode normal NULL +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO TriangleSet2D [ #%NDT=SFWorldNode,SFGeometryNode +exposedField MFVec2f vertices [] +#field SFBool solid FALSE +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO TriangleStripSet [ #%NDT=SFWorldNode,SFGeometryNode +exposedField SFColorNode color NULL +exposedField SFCoordinateNode coord NULL +exposedField SFNormalNode normal NULL +exposedField MFInt32 stripCount [] +exposedField SFTextureCoordinateNode texCoord NULL +field SFBool ccw TRUE +field SFBool colorPerVertex TRUE +field SFBool normalPerVertex TRUE +field SFBool solid TRUE +exposedField SFMetadataNode metadata NULL +] { +} + +PROTO Viewpoint [ #%NDT=SFWorldNode,SF3DNode,SFViewpointNode +eventIn SFBool set_bind +exposedField SFFloat fieldOfView 0.785398 +exposedField SFBool jump TRUE +exposedField SFRotation orientation 0 0 1 0 +exposedField SFVec3f position 0 0 10 +field SFString description "" +eventOut SFTime bindTime +eventOut SFBool isBound +#X3D extensions +exposedField SFMetadataNode metadata NULL +exposedField SFVec3f centerOfRotation 0 0 0 +] { +} + + +PROTO VisibilitySensor [ #%NDT=SFWorldNode,SF3DNode +exposedField SFVec3f center 0 0 0 +exposedField SFBool enabled TRUE +exposedField SFVec3f size 0 0 0 +eventOut SFTime enterTime +eventOut SFTime exitTime +eventOut SFBool isActive +#X3D extensions +exposedField SFMetadataNode metadata NULL +]{ +} + +PROTO WorldInfo [ #%NDT=SFWorldNode,SF2DNode,SF3DNode +field MFString info [] +field SFString title "" +#X3D extensions +exposedField SFMetadataNode metadata NULL +] { +} diff --git a/applications/m3u82mpd/m3u82mpd.vcproj b/applications/m3u82mpd/m3u82mpd.vcproj new file mode 100644 index 0000000..1887aca --- /dev/null +++ b/applications/m3u82mpd/m3u82mpd.vcproj @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/m3u82mpd/main.c b/applications/m3u82mpd/main.c new file mode 100644 index 0000000..2c161d5 --- /dev/null +++ b/applications/m3u82mpd/main.c @@ -0,0 +1,122 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Copyright (c) Telecom ParisTech 2010 - + * All rights reserved + * + * This file is part of GPAC / m3u82mpd application + * + * GPAC is gf_free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include + + +int main(int argc, char **argv) +{ + GF_Err e; + VariantPlaylist * pl = NULL; + char *url = argv[1]; + //char *cache_m3u8_file; + u32 i, count; + FILE *fmpd; + Bool verbose = 0; + u32 update_interval = 0; + char *m3u8_local_name = "file.m3u8"; + Bool is_local = 0; + + gf_sys_init(0); + + gf_log_set_tool_level(GF_LOG_NETWORK, verbose ? GF_LOG_DEBUG : GF_LOG_INFO); + + while (1) { + + if (gf_url_is_local(url)) { + m3u8_local_name = url; + is_local = 1; + } else { + e = gf_dm_wget(url, m3u8_local_name, 0, 0); + if (e != GF_OK) return -1; + } + + e = parse_root_playlist(m3u8_local_name, &pl, "."); + if (e != GF_OK) return -1; + + fmpd = gf_fopen(argv[2], "wt"); + + fprintf(fmpd, "\n"); + fprintf(fmpd, " \n"); + fprintf(fmpd, " Media Presentation Description for file %s\n", url); + fprintf(fmpd, " Generated by GPAC %s\n", GPAC_FULL_VERSION); + + fprintf(fmpd, " \n"); + fprintf(fmpd, " \n"); + + count = gf_list_count(pl->programs); + for (i=0; iprograms, i); + count2 = gf_list_count(prog->bitrates); + for (j = 0; jbitrates, j); + fprintf(stdout, "%d, %d, %s, %s, %d\n", pe->durationInfo, pe->bandwidth, pe->title, pe->url, pe->elementType); + if (pe->elementType == TYPE_PLAYLIST) { + u32 k, count3; + char *tmp; + char c; + char baseURL[GF_MAX_PATH]; + tmp = strrchr(url, '/'); + if (tmp) { + tmp++; + c = tmp[0]; + tmp[0] = 0; + strcpy(baseURL, url); + tmp[0] = c; + } else { + baseURL[0] = 0; + } + fprintf(fmpd, " \n"); + fprintf(fmpd, " durationInfo); + if (baseURL[0]) fprintf(fmpd, "baseURL=\"%s\"", baseURL); + fprintf(fmpd, ">\n"); + count3 = gf_list_count(pe->element.playlist.elements); + update_interval = (count3 - 1) * pe->durationInfo * 1000; + for (k=0; kelement.playlist.elements, k); + if (k) fprintf(fmpd, " \n", elt->url); + else fprintf(fmpd, " \n", elt->url); + } + fprintf(fmpd, " \n"); + fprintf(fmpd, " \n"); + } else if (pe->elementType == TYPE_STREAM) { + fprintf(stdout, "Stream\n"); + } + } + } + fprintf(fmpd, " \n"); + fprintf(fmpd, ""); + gf_fclose(fmpd); + variant_playlist_del(pl); + if (is_local) break; + gf_sleep(update_interval); + } + + gf_sys_close(); + return 0; +} diff --git a/applications/mp42avi/Makefile b/applications/mp42avi/Makefile new file mode 100644 index 0000000..ebaf44c --- /dev/null +++ b/applications/mp42avi/Makefile @@ -0,0 +1,48 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/applications/mp42avi + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o + + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=MP42Avi$(EXE) +else +EXT= +PROG=MP42Avi +endif + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/$(TARGET_BIN_DIR) -lgpac -lz + +clean: + rm -f $(OBJS) ../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/mp42avi/main.c b/applications/mp42avi/main.c new file mode 100644 index 0000000..4b6c057 --- /dev/null +++ b/applications/mp42avi/main.c @@ -0,0 +1,785 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2000-2012 + * All rights reserved + * + * This file is part of GPAC / command-line mp4 toolbox + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#define GPAC_CFG_FILE "GPAC.cfg" +#else +#include +typedef struct tagBITMAPFILEHEADER +{ + u16 bfType; + u32 bfSize; + u16 bfReserved1; + u16 bfReserved2; + u32 bfOffBits; +} BITMAPFILEHEADER; + +typedef struct tagBITMAPINFOHEADER { + u32 biSize; + s32 biWidth; + s32 biHeight; + u16 biPlanes; + u16 biBitCount; + u32 biCompression; + u32 biSizeImage; + s32 biXPelsPerMeter; + s32 biYPelsPerMeter; + u32 biClrUsed; + u32 biClrImportant; +} BITMAPINFOHEADER; + +#define BI_RGB 0L + +#define GPAC_CFG_FILE ".gpacrc" +#endif + +#include +#include + +void PrintVersion() +{ + printf ("MP42AVI - GPAC version %s\n", GPAC_FULL_VERSION); +} + +void PrintUsage() +{ + printf ("MP42AVI [option] input\n" + "Dumps BIFS media frames as AVI, BMP or raw\n\n" + "Options\n" + "-fps Framerate: specifies extraction framerate - if not set computed from track length\n" + "-size WxH: forces output BIFS to the given resolution\n" + "-raw [frame]: uses raw format for output - only dumps one frame if specified\n" + "-bmp [frame]: uses BMP format for output - only dumps one frame if specified\n" + "-outpath path: specifies where to dump frames/movie\n" + "\n" + "Note: when dumping a frame, either the frame number can be specified or the frame time\n" + "in the format hh:mm:ss:xFz where hh, mm, ss are hours, minutes, seconds, x the number\n" + "of the frame in the seconds and z the frame rate used to express the time\n" + "\n" + "-cfg: specifies path to GPAC config file (GPAC.cfg)\n" + "-v: prints version\n" + "-h: prints this message\n" + "\nWritten by Jean Le Feuvre - (c) 2000-2005\n"); +} + + +typedef struct +{ + GF_Compositor *sr; + GF_SceneGraph *sg; + GF_BifsDecoder *bifs; + GF_ISOFile *file; + + u32 track; + u64 duration, cts; +} BIFSVID; + +void node_init(void *cbk, GF_Node *node) +{ + BIFSVID *b2v = cbk; + switch (gf_node_get_tag(node)) { + case TAG_MPEG4_Conditional: + case TAG_MPEG4_QuantizationParameter: + break; + default: + if (b2v->sr) gf_sc_on_node_init(b2v->sr, node); + break; + } +} + +void node_modif(void *cbk, GF_Node *node) +{ + BIFSVID *b2v = cbk; + if (b2v->sr) gf_sc_invalidate(b2v->sr, node); +} + +Double get_scene_time(void *cbk) +{ + Double res; + BIFSVID *b2v = cbk; + res = (Double) (s64) b2v->cts; + res /= (Double) (s64) b2v->duration; + return res; +} + +void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) +{ + char str[GF_MAX_PATH]; + BITMAPFILEHEADER fh; + BITMAPINFOHEADER fi; + FILE *fout; + u32 j, i; + char *ptr; + + if (img_num<10) { + sprintf(str, "%s_00%d.bmp", rad_name, img_num); + } else if (img_num<100) { + sprintf(str, "%s_0%d.bmp", rad_name, img_num); + } else { + sprintf(str, "%s_%d.bmp", rad_name, img_num); + } + + fout = gf_fopen(str, "wb"); + if (!fout) return; + + memset(&fh, 0, sizeof(fh)); + fh.bfType = 19778; + fh.bfOffBits = 14 + 40; + + memset(&fi, 0, sizeof(char)*40); + fi.biSize = sizeof(char)*40; + fi.biWidth = fb->width; + fi.biHeight = fb->height; + fi.biPlanes = 1; + fi.biBitCount = 24; + fi.biCompression = BI_RGB; + fi.biSizeImage = fb->pitch * fb->height; + + /*NOT ALIGNED!!*/ + gf_fwrite(&fh.bfType, 2, 1, fout); + gf_fwrite(&fh.bfSize, 4, 1, fout); + gf_fwrite(&fh.bfReserved1, 2, 1, fout); + gf_fwrite(&fh.bfReserved2, 2, 1, fout); + gf_fwrite(&fh.bfOffBits, 4, 1, fout); + + gf_fwrite(&fi, 1, 40, fout); + + for (j=fb->height; j>0; j--) { + ptr = fb->video_buffer + (j-1)*fb->pitch; + //gf_fwrite(ptr, 1, fb->width * 3, fout); + for (i=0; iwidth; i++) { + fputc(ptr[2], fout); + fputc(ptr[1], fout); + fputc(ptr[0], fout); + ptr+=3; + } + } + + gf_fclose(fout); +} + + +void write_raw(GF_VideoSurface *fb, char *rad_name, u32 img_num) +{ + char str[GF_MAX_PATH]; + FILE *fout; + if (img_num<10) { + sprintf(str, "%s_00%d.raw", rad_name, img_num); + } else if (img_num<100) { + sprintf(str, "%s_0%d.raw", rad_name, img_num); + } else { + sprintf(str, "%s_%d.raw", rad_name, img_num); + } + + fout = gf_fopen(str, "wb"); + if (!fout) return; + gf_fwrite(fb->video_buffer , fb->height*fb->pitch, 1, fout); + gf_fclose(fout); +} + +void dump_frame(BIFSVID b2v, char *conv_buf, char *out_path, u32 dump_type, avi_t *avi_out, u32 frameNum) +{ + u32 k; + GF_VideoSurface fb; + + /*lock it*/ + gf_sc_get_screen_buffer(b2v.sr, &fb); + /*export frame*/ + switch (dump_type) { + case 0: + /*reverse frame*/ + for (k=0; kdependsOnESID && (esd->decoderConfig->streamType == GF_STREAM_SCENE)) break; + gf_odf_desc_del((GF_Descriptor *) esd); + esd = NULL; + } + if (!esd) { + printf("no bifs track found\n"); + goto err_exit; + } + + es_id = (u16) gf_isom_get_track_id(file, track_number+1); + e = gf_bifs_decoder_configure_stream(b2v.bifs, es_id, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, esd->decoderConfig->objectTypeIndication); + if (e) { + printf("BIFS init error %s\n", gf_error_to_string(e)); + gf_odf_desc_del((GF_Descriptor *) esd); + esd = NULL; + goto err_exit; + } + + { + GF_ISOSample *samp = gf_isom_get_sample(file, track_number+1, 1, &di); + b2v.cts = samp->DTS + samp->CTS_Offset; + /*apply command*/ + gf_bifs_decode_au(b2v.bifs, es_id, samp->data, samp->dataLength, ((Double)(s64)b2v.cts)/1000.0); + gf_isom_sample_del(&samp); + } + + b2v.duration = gf_isom_get_media_duration(file, track_number+1); + + gf_odf_desc_del((GF_Descriptor *) esd); + + } + gf_sc_set_scene(b2v.sr, b2v.sg); + + if (!width || !height) { + gf_sg_get_scene_size_info(b2v.sg, &width, &height); + } + /*we work in RGB24, and we must make sure the pitch is %4*/ + if ((width*3)%4) { + printf("Adjusting width (%d) to have a stride multiple of 4\n", width); + while ((width*3)%4) width--; + } + gf_sc_set_size(b2v.sr, width, height); + gf_sc_get_screen_buffer(b2v.sr, &fb); + width = fb.width; + height = fb.height; + gf_sc_release_screen_buffer(b2v.sr, &fb); + + GF_SAFEALLOC(rendered_frames, nb_viewpoints*sizeof(char *)); + for (viewpoint_index = 1; viewpoint_index <= nb_viewpoints; viewpoint_index++) { + GF_SAFEALLOC(rendered_frames[viewpoint_index-1], fb.width*fb.height*3); + gf_sc_set_viewpoint(b2v.sr, viewpoint_index, NULL); + gf_sc_draw_frame(b2v.sr, 0, NULL); + /*needed for background2D !!*/ + gf_sc_draw_frame(b2v.sr, 0, NULL); + strcpy(out_path, ""); + if (out_dir) { + strcat(out_path, out_dir); + if (out_path[strlen(out_path)-1] != '\\') strcat(out_path, "\\"); + } + strcat(out_path, rad_name); + strcat(out_path, "_view"); + gf_sc_get_screen_buffer(b2v.sr, &fb); + write_bmp(&fb, out_path, viewpoint_index); + memcpy(rendered_frames[viewpoint_index-1], fb.video_buffer, fb.width*fb.height*3); + gf_sc_release_screen_buffer(b2v.sr, &fb); + } + + if (width != 800 || height != 480) { + printf("Wrong scene dimension, cannot produce output\n"); + goto err_exit; + } else { + u32 x, y; + GF_VideoSurface out_fb; + u32 bpp = 3; + out_fb.width = 800; + out_fb.height = 480; + out_fb.pitch = 800*bpp; + out_fb.pixel_format = GF_PIXEL_RGB_24; + out_fb.is_hardware_memory = 0; + GF_SAFEALLOC(out_fb.video_buffer, out_fb.pitch*out_fb.height) +#if 1 + for (y=0; ydependsOnESID && (esd->decoderConfig->streamType == GF_STREAM_SCENE)) break; + gf_odf_desc_del((GF_Descriptor *) esd); + esd = NULL; + } + if (!esd) { + printf("no bifs track found\n"); + goto err_exit; + } + + b2v.duration = gf_isom_get_media_duration(file, i+1); + timescale = gf_isom_get_media_timescale(file, i+1); + es_id = (u16) gf_isom_get_track_id(file, i+1); + e = gf_bifs_decoder_configure_stream(b2v.bifs, es_id, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, esd->decoderConfig->objectTypeIndication); + if (e) { + printf("BIFS init error %s\n", gf_error_to_string(e)); + gf_odf_desc_del((GF_Descriptor *) esd); + esd = NULL; + goto err_exit; + } + if (dump_time>=0) dump_time = dump_time *1000 / timescale; + + gf_sc_set_scene(b2v.sr, b2v.sg); + count = gf_isom_get_sample_count(file, i+1); + + reset_fps = 0; + if (!fps) { + fps = (Float) (count * timescale); + fps /= (Double) (s64) b2v.duration; + printf("Estimated BIFS FrameRate %g\n", fps); + reset_fps = 1; + } + + if (!width || !height) { + gf_sg_get_scene_size_info(b2v.sg, &width, &height); + } + /*we work in RGB24, and we must make sure the pitch is %4*/ + if ((width*3)%4) { + printf("Adjusting width (%d) to have a stride multiple of 4\n", width); + while ((width*3)%4) width--; + } + + gf_sc_set_size(b2v.sr, width, height); + gf_sc_draw_frame(b2v.sr, 0, NULL); + + gf_sc_get_screen_buffer(b2v.sr, &fb); + width = fb.width; + height = fb.height; + if (avi_out) { + AVI_set_video(avi_out, width, height, fps, comp); + conv_buf = gf_malloc(sizeof(char) * width * height * 3); + } + printf("Dumping at BIFS resolution %d x %d\n\n", width, height); + gf_sc_release_screen_buffer(b2v.sr, &fb); + + cur_time = 0; + + duration = (u32)(timescale / fps); + if (reset_fps) fps = 0; + + frameNum = 1; + first_dump = 1; + for (j=0; jDTS + samp->CTS_Offset; + /*apply command*/ + gf_bifs_decode_au(b2v.bifs, es_id, samp->data, samp->dataLength, ((Double)(s64)b2v.cts)/1000.0); + gf_isom_sample_del(&samp); + + if ((frameID>=0) && (j<(u32)frameID)) continue; + if ((dump_time>=0) && ((u32) dump_time>b2v.cts)) continue; + /*render frame*/ + gf_sc_draw_frame(b2v.sr, 0, NULL); + /*needed for background2D !!*/ + if (first_dump) { + gf_sc_draw_frame(b2v.sr, 0, NULL); + first_dump = 0; + } + + if (fps) { + if (cur_time > b2v.cts) continue; + + while (1) { + printf("dumped frame time %f (frame %d - sample %d)\r", ((Float)cur_time)/timescale, frameNum, j+1); + dump_frame(b2v, conv_buf, config_path, dump_type, avi_out, frameNum); + frameNum++; + cur_time += duration; + if (cur_time > b2v.cts) break; + } + } else { + dump_frame(b2v, conv_buf, config_path, dump_type, avi_out, (frameID>=0) ? frameID : frameNum); + if (frameID>=0 || dump_time>=0) break; + frameNum++; + printf("dumped frame %d / %d\r", j+1, count); + } + + } + gf_odf_desc_del((GF_Descriptor *) esd); + + /*destroy everything*/ + gf_bifs_decoder_del(b2v.bifs); + gf_sg_del(b2v.sg); + gf_sc_set_scene(b2v.sr, NULL); + gf_sc_del(b2v.sr); + +err_exit: + if (avi_out) AVI_close(avi_out); + if (conv_buf) gf_free(conv_buf); + if (user.modules) gf_modules_del(user.modules); + if (needs_raw) gf_cfg_set_key(user.config, "Video", "DriverName", old_driv); + gf_cfg_del(user.config); +} + +int main (int argc, char **argv) +{ + Double fps_dump; + u32 i; + char rad[500]; + s32 frameID, h, m, s, f; + Float fps; + u32 dump_type; + s32 dump_time; + u32 dump_w, dump_h; + Bool copy; + char szConfigFile[4096]; + char *dump_out; + char *inName, *arg; + GF_ISOFile *file; + + if (argc < 2) { + PrintUsage(); + return 0; + } + + dump_type = 0; + fps_dump = 0.0f; + dump_w = dump_h = 0; + dump_out = NULL; + inName = NULL; + frameID = -1; + dump_time = -1; + szConfigFile[0] = 0; + + for (i = 1; i < (u32) argc ; i++) { + arg = argv[i]; + if (arg[0] != '-') { + inName = arg; + break; + } + if (!stricmp(arg, "-h")) { + PrintUsage(); + return 0; + } else if (!stricmp(arg, "-version")) { + PrintVersion(); + return 0; + } else if (!stricmp(arg, "-size")) { + sscanf(argv[i+1], "%dx%d", &dump_w, &dump_h); + i++; + } else if (!stricmp(arg, "-raw")) { + dump_type = 2; + if ((i+1<(u32)argc) && (argv[i+1][0]!='-')) { + if (strstr(argv[i+1], "T")) { + if (strstr(argv[i+1], "F")) { + sscanf(argv[i+1], "T%d:%d:%d:%dF%f", &h, &m, &s, &f, &fps); + dump_time = (s32) ((3600*h + 60*m + s)*1000 + 1000*f/fps); + } else { + sscanf(argv[i+1], "T%d:%d:%d", &h, &m, &s); + dump_time = (s32) ((3600*h + 60*m + s)*1000); + } + } else { + frameID = atoi(argv[i+1]); + } + i++; + } + } else if (!stricmp(arg, "-bmp")) { + dump_type = 1; + if ((i+1<(u32)argc) && (argv[i+1][0]!='-')) { + if (strstr(argv[i+1], "T")) { + if (strstr(argv[i+1], "F")) { + sscanf(argv[i+1], "T%d:%d:%d:%dF%f", &h, &m, &s, &f, &fps); + dump_time = (s32) ((3600*h + 60*m + s)*1000 + 1000*f/fps); + } else { + sscanf(argv[i+1], "T%d:%d:%d", &h, &m, &s); + dump_time = (s32) ((3600*h + 60*m + s)*1000); + } + } else { + frameID = atoi(argv[i+1]); + } + i++; + } + } else if (!stricmp(arg, "-3d")) { + dump_type = 3; + } else if (!stricmp(arg, "-outpath")) { + dump_out = argv[i+1]; + i++; + } else if (!stricmp(arg, "-fps")) { + fps_dump = atof(argv[i+1]); + i++; + } else if (!stricmp(arg, "-copy")) { + copy = 1; + } else if (!stricmp(arg, "-cfg")) { + strcpy(szConfigFile, argv[i+1]); + i += 1; + } else { + PrintUsage(); + return (0); + } + } + if (!inName) { + PrintUsage(); + return 0; + } + gf_sys_init(); + + file = gf_isom_open(inName, GF_ISOM_OPEN_READ, NULL); + if (!file) { + printf("Error opening file: %s\n", gf_error_to_string(gf_isom_last_error(NULL))); + return 0; + } + + if (dump_out) { + arg = strrchr(inName, GF_PATH_SEPARATOR); + if (arg) { + strcpy(rad, arg + 1); + } else { + strcpy(rad, inName); + } + } else { + strcpy(rad, inName); + } + while (rad[strlen(rad)-1] != '.') rad[strlen(rad)-1] = 0; + rad[strlen(rad)-1] = 0; + if (dump_type == 3) { + bifs3d_viewpoints_merger(file, szConfigFile, dump_w, dump_h, rad, dump_type, dump_out, fps_dump, frameID, dump_time); + } + else bifs_to_vid(file, szConfigFile, dump_w, dump_h, rad, dump_type, dump_out, fps_dump, frameID, dump_time); + printf("\ndone\n"); + gf_isom_delete(file); + return 0; + +} + diff --git a/applications/mp42ts/Makefile b/applications/mp42ts/Makefile new file mode 100644 index 0000000..c8b88db --- /dev/null +++ b/applications/mp42ts/Makefile @@ -0,0 +1,50 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/applications/mp42ts + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o + +LINKFLAGS=-L../../bin/gcc +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=MP42TS$(EXE) +else +EXT= +PROG=MP42TS +endif +LINKFLAGS+=-lgpac + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/mp42ts/main.c b/applications/mp42ts/main.c new file mode 100644 index 0000000..eba445d --- /dev/null +++ b/applications/mp42ts/main.c @@ -0,0 +1,2755 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre, Cyril Concolato, Romain Bouqueau + * Copyright (c) Telecom ParisTech 2005-2012 + * All rights reserved + * + * This file is part of GPAC / mp4-to-ts (mp42ts) application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#ifndef GPAC_DISABLE_STREAMING +#include +#endif + +#ifndef GPAC_DISABLE_SENG +#include +#endif + +#ifndef GPAC_DISABLE_TTXT +#include +#endif + + +#ifdef GPAC_DISABLE_MPEG2TS_MUX +#error "Cannot compile MP42TS if GPAC is not built with MPEG2-TS Muxing support" +#endif + +#define MP42TS_PRINT_TIME_MS 500 /*refresh printed info every CLOCK_REFRESH ms*/ +#define MP42TS_VIDEO_FREQ 1000 /*meant to send AVC IDR only every CLOCK_REFRESH ms*/ + +u32 temi_url_insertion_delay = 1000; +u32 temi_offset = 0; +Bool temi_disable_loop = 0; +FILE *logfile = NULL; + +static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) +{ + FILE *logs = cbk; + vfprintf(logs, fmt, list); + fflush(logs); +} + +static GFINLINE void usage() +{ + fprintf(stderr, "GPAC version " GPAC_FULL_VERSION "\n" + "GPAC Copyright (c) Telecom ParisTech 2000-2014\n" + "GPAC Configuration: " GPAC_CONFIGURATION "\n" + "Features: %s\n\n", gpac_features()); + fprintf(stderr, "mp42ts [options]\n" + "\n" + "Inputs:\n" + "-src filename[:OPTS] specifies an input file used for a TS service\n" + " * currently only supports ISO files and SDP files\n" + " * can be used several times, once for each program\n" + "By default each source is a program in a TS. \n" + "Source options are colon-separated list of options, as follows:\n" + "ID=N specifies the program ID for this source.\n" + " All sources with the same ID will be added to the same program\n" + "name=STR program name, as used in DVB service description table\n" + "provider=STR provider name, as used in DVB service description table\n" + + "\n" + "-prog filename same as -src filename\n" + "\n" + "Destinations:\n" + "Several destinations may be specified as follows, at least one is mandatory\n" + "-dst-udp UDP_address:port (multicast or unicast)\n" + "-dst-rtp RTP_address:port\n" + "-dst-file filename\n" + "The following parameters may be specified when -dst-file is used\n" + "-segment-dir dir server local directory to store segments (ends with a '/')\n" + "-segment-duration dur segment duration in seconds\n" + "-segment-manifest file m3u8 file basename\n" + "-segment-http-prefix p client address for accessing server segments\n" + "-segment-number n number of segments to list in the manifest\n" + "\n" + "Basic options:\n" + "-rate R specifies target rate in kbps of the multiplex (optional)\n" + "-real-time specifies the muxer will work in real-time mode\n" + " * if not specified, the muxer will generate the TS as quickly as possible\n" + " * automatically set for SDP or BT input\n" + "-pcr-init V sets initial value V for PCR - if not set, random value is used\n" + "-pcr-offset V offsets all timestamps from PCR by V, in 90kHz. Default value is computed based on input media.\n" + "-psi-rate V sets PSI refresh rate V in ms (default 100ms).\n" + " * If 0, PSI data is only send once at the beginning or before each IDR when -rap option is set.\n" + " * This should be set to 0 for DASH streams.\n" + "-time n request the muxer to stop after n ms\n" + "-single-au forces 1 PES = 1 AU (disabled by default)\n" + "-rap forces RAP/IDR to be aligned with PES start for video streams (disabled by default)\n" + " in this mode, PAT, PMT and PCR will be inserted before the first TS packet of the RAP PES\n" + "-flush-rap same as -rap but flushes all other streams (sends remaining PES packets) before inserting PAT/PMT\n" + "-nb-pack N specifies to pack up to N TS packets together before sending on network or writing to file\n" + "-pcr-ms N sets max interval in ms between 2 PCR. Default is 100 ms\n" + "-ttl N specifies Time-To-Live for multicast. Default is 1.\n" + "-ifce IPIFCE specifies default IP interface to use. Default is IF_ANY.\n" + "-temi [URL] Inserts TEMI time codes in adaptation field. URL is optionnal\n" + "-temi-delay DelayMS Specifies delay between two TEMI url descriptors (default is 1000)\n" + "-temi-offset OffsetMS Specifies an offset in ms to add to TEMI (by default TEMI starts at 0)\n" + "-temi-noloop Do not restart the TEMI timeline at the end of the source\n" + "-sdt-rate MS Gives the SDT carrousel rate in milliseconds. If 0 (default), SDT is not sent\n" + "\n" + "MPEG-4/T-DMB options:\n" + "-bifs-src filename update file: must be either an .sdp or a .bt file\n" + "-audio url may be mp3/udp or aac/http (shoutcast/icecast)\n" + "-video url shall be a raw h264 frame\n" + "-mpeg4-carousel n carousel period in ms\n" + "-mpeg4 or -4on2 forces usage of MPEG-4 signaling (IOD and SL Config)\n" + "-4over2 same as -4on2 and uses PMT to carry OD Updates\n" + "-bifs-pes carries BIFS over PES instead of sections\n" + "-bifs-pes-ex carries BIFS over PES without writing timestamps in SL\n" + "\n" + "Misc options\n" +#ifdef GPAC_MEMORY_TRACKING + "-mem-track enables memory tracker\n" +#endif + "-logs set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" + "-h or -help print this screen\n" + "\n" + ); +} + + +#define MAX_MUX_SRC_PROG 100 +typedef struct +{ + +#ifndef GPAC_DISABLE_ISOM + GF_ISOFile *mp4; +#endif + + u32 nb_streams, pcr_idx; + GF_ESInterface streams[40]; + GF_Descriptor *iod; +#ifndef GPAC_DISABLE_SENG + GF_SceneEngine *seng; +#endif + GF_Thread *th; + char *bifs_src_name; + u32 rate; + Bool repeat; + u32 mpeg4_signaling; + Bool audio_configured; + u64 samples_done, samples_count; + u32 nb_real_streams; + Bool real_time; + GF_List *od_updates; + + u32 max_sample_size; + + char program_name[20]; + char provider_name[20]; + u32 ID; + Bool is_not_program_declaration; + + Double last_ntp; +} M2TSSource; + +#ifndef GPAC_DISABLE_ISOM +typedef struct +{ + GF_ISOFile *mp4; + u32 track, sample_number, sample_count; + u32 mstype, mtype; + GF_ISOSample *sample; + /*refresh rate for images*/ + u32 image_repeat_ms, nb_repeat_last; + void *dsi; + u32 dsi_size; + + void *dsi_and_rap; + Bool loop; + Bool is_repeat; + s64 ts_offset; + M2TSSource *source; + + const char *temi_url; + u32 last_temi_url; + Bool insert_temi; + Bool insert_ntp; + +} GF_ESIMP4; +#endif + +typedef struct +{ + u32 carousel_period, ts_delta; + u16 aggregate_on_stream; + Bool adjust_carousel_time; + Bool discard; + Bool rap; + Bool critical; + Bool vers_inc; +} GF_ESIStream; + +typedef struct +{ + u32 size; + char *data; +} GF_SimpleDataDescriptor; + +//TODO: find a clean way to save this data +#ifndef GPAC_DISABLE_PLAYER +static u32 audio_OD_stream_id = (u32)-1; +#endif + +#define AUDIO_OD_ESID 100 +#define AUDIO_DATA_ESID 101 +#define VIDEO_DATA_ESID 105 + +/*output types*/ +enum +{ + GF_MP42TS_FILE, /*open mpeg2ts file*/ + GF_MP42TS_UDP, /*open udp socket*/ + GF_MP42TS_RTP, /*open rtp socket*/ +#ifndef GPAC_DISABLE_PLAYER + GF_MP42TS_HTTP, /*open http downloader*/ +#endif +}; + +static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 ntp, const char *temi_url, u32 *last_url_time) +{ + u32 res; + u32 len; + u32 last_time; + GF_BitStream *bs = gf_bs_new(af_data, 188, GF_BITSTREAM_WRITE); + + if (ntp) { + last_time = 1000*(ntp>>32); + last_time += 1000*(ntp&0xFFFFFFFF)/0xFFFFFFFF; + } else { + last_time = (u32) (1000*timecode/timescale); + } + if (temi_url && (!*last_url_time || (last_time - *last_url_time + 1 >= temi_url_insertion_delay)) ) { + *last_url_time = last_time + 1; + len = 0; + gf_bs_write_int(bs, GF_M2TS_AFDESC_LOCATION_DESCRIPTOR, 8); + gf_bs_write_int(bs, len, 8); + + gf_bs_write_int(bs, 0, 1); //force_reload + gf_bs_write_int(bs, 0, 1); //is_announcement + gf_bs_write_int(bs, 0, 1); //splicing_flag + gf_bs_write_int(bs, 0, 1); //use_base_temi_url + gf_bs_write_int(bs, 0xFF, 5); //reserved + gf_bs_write_int(bs, 0, 7); //timeline_id + + if (strlen(temi_url)) { + char *url = (char *)temi_url; + if (!strnicmp(temi_url, "http://", 7)) { + gf_bs_write_int(bs, 1, 8); //url_scheme + url = (char *) temi_url + 7; + } else if (!strnicmp(temi_url, "https://", 8)) { + gf_bs_write_int(bs, 2, 8); //url_scheme + url = (char *) temi_url + 8; + } else { + gf_bs_write_int(bs, 0, 8); //url_scheme + } + gf_bs_write_u8(bs, (u32) strlen(url)); //url_path_len + gf_bs_write_data(bs, url, (u32) strlen(url) ); //url + gf_bs_write_u8(bs, 0); //nb_addons + } + //rewrite len + len = (u32) gf_bs_get_position(bs) - 2; + af_data[1] = len; + } + + if (timescale || ntp) { + Bool use64 = (timecode > 0xFFFFFFFFUL) ? 1 : 0; + len = 3; //3 bytes flags + + if (timescale) len += 4 + (use64 ? 8 : 4); + if (ntp) len += 8; + + //write timeline descriptor + gf_bs_write_int(bs, GF_M2TS_AFDESC_TIMELINE_DESCRIPTOR, 8); + gf_bs_write_int(bs, len, 8); + + gf_bs_write_int(bs, timescale ? (use64 ? 2 : 1) : 0, 2); //has_timestamp + gf_bs_write_int(bs, ntp ? 1 : 0, 1); //has_ntp + gf_bs_write_int(bs, 0, 1); //has_ptp + gf_bs_write_int(bs, 0, 2); //has_timecode + gf_bs_write_int(bs, 0, 1); //force_reload + gf_bs_write_int(bs, 0, 1); //paused + gf_bs_write_int(bs, 0, 1); //discontinuity + gf_bs_write_int(bs, 0xFF, 7); //reserved + gf_bs_write_int(bs, temi_url ? 0 : 150, 8); //timeline_id + if (timescale) { + gf_bs_write_u32(bs, timescale); //timescale + if (use64) + gf_bs_write_u64(bs, timecode); //timestamp + else + gf_bs_write_u32(bs, (u32) timecode); //timestamp + } + if (ntp) { + gf_bs_write_u64(bs, ntp); //ntp + } + } + res = (u32) gf_bs_get_position(bs); + gf_bs_del(bs); + return res; +} + +#ifndef GPAC_DISABLE_ISOM + +static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) +{ + char af_data[188]; + GF_ESIMP4 *priv = (GF_ESIMP4 *)ifce->input_udta; + if (!priv) return GF_BAD_PARAM; + + switch (act_type) { + case GF_ESI_INPUT_DATA_FLUSH: + { + GF_ESIPacket pck; +#ifndef GPAC_DISABLE_TTXT + GF_List *cues = NULL; +#endif + if (!priv->sample) + priv->sample = gf_isom_get_sample(priv->mp4, priv->track, priv->sample_number+1, NULL); + + if (!priv->sample) { + return GF_IO_ERR; + } + + memset(&pck, 0, sizeof(GF_ESIPacket)); + + pck.flags = GF_ESI_DATA_AU_START | GF_ESI_DATA_HAS_CTS; + if (priv->sample->IsRAP) pck.flags |= GF_ESI_DATA_AU_RAP; + pck.cts = priv->sample->DTS + priv->ts_offset; + if (priv->is_repeat) pck.flags |= GF_ESI_DATA_REPEAT; + + if (priv->insert_temi) { + u64 ntp=0; + u64 tc = priv->sample->DTS + priv->sample->CTS_Offset; + if (temi_disable_loop) { + tc += priv->ts_offset; + } + + if (temi_offset) { + tc += ((u64) temi_offset) * ifce->timescale / 1000; + } + + if (priv->insert_ntp) { + u32 sec, frac; + gf_net_get_ntp(&sec, &frac); + ntp = sec; + ntp <<= 32; + ntp |= frac; + } + pck.mpeg2_af_descriptors_size = format_af_descriptor(af_data, tc, ifce->timescale, ntp, priv->temi_url, &priv->last_temi_url); + pck.mpeg2_af_descriptors = af_data; + } + + if (priv->nb_repeat_last) { + pck.cts += priv->nb_repeat_last*ifce->timescale * priv->image_repeat_ms / 1000; + } + + pck.dts = pck.cts; + if (priv->sample->CTS_Offset) { + pck.cts += priv->sample->CTS_Offset; + pck.flags |= GF_ESI_DATA_HAS_DTS; + } + + if (priv->sample->IsRAP && priv->dsi && priv->dsi_size) { + pck.data = priv->dsi; + pck.data_len = priv->dsi_size; + ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck); + pck.flags &= ~GF_ESI_DATA_AU_START; + } + + pck.flags |= GF_ESI_DATA_AU_END; + pck.data = priv->sample->data; + pck.data_len = priv->sample->dataLength; + pck.duration = gf_isom_get_sample_duration(priv->mp4, priv->track, priv->sample_number+1); +#ifndef GPAC_DISABLE_TTXT + if (priv->mtype==GF_ISOM_MEDIA_TEXT && priv->mstype==GF_ISOM_SUBTYPE_WVTT) { + u64 start; + GF_WebVTTCue *cue; + GF_List *gf_webvtt_parse_iso_cues(GF_ISOSample *iso_sample, u64 start); + start = (priv->sample->DTS * 1000) / ifce->timescale; + cues = gf_webvtt_parse_iso_cues(priv->sample, start); + if (gf_list_count(cues)>1) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS Muxer] More than one cue in sample\n")); + } + cue = (GF_WebVTTCue *)gf_list_get(cues, 0); + if (cue) { + pck.data = cue->text; + pck.data_len = (u32)strlen(cue->text)+1; + } else { + pck.data = NULL; + pck.data_len = 0; + } + } +#endif + ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS Muxer] Track %d: sample %d CTS %d\n", priv->track, priv->sample_number+1, pck.cts)); + +#ifndef GPAC_DISABLE_TTXT + if (cues) { + while (gf_list_count(cues)) { + GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, 0); + gf_list_rem(cues, 0); + gf_webvtt_cue_del(cue); + } + gf_list_del(cues); + cues = NULL; + } +#endif + gf_isom_sample_del(&priv->sample); + priv->sample_number++; + + if (!priv->source->real_time && !priv->is_repeat) { + priv->source->samples_done++; + gf_set_progress("Converting to MPEG-2 TS", priv->source->samples_done, priv->source->samples_count); + } + + if (priv->sample_number==priv->sample_count) { + if (priv->loop) { + Double scale; + u64 duration; + /*increment ts offset*/ + scale = gf_isom_get_media_timescale(priv->mp4, priv->track); + scale /= gf_isom_get_timescale(priv->mp4); + duration = (u64) (gf_isom_get_duration(priv->mp4) * scale); + priv->ts_offset += duration; + priv->sample_number = 0; + priv->is_repeat = (priv->sample_count==1) ? 1 : 0; + } + else if (priv->image_repeat_ms && priv->source->nb_real_streams) { + priv->nb_repeat_last++; + priv->sample_number--; + priv->is_repeat = 1; + } else { + if (!(ifce->caps & GF_ESI_STREAM_IS_OVER)) { + ifce->caps |= GF_ESI_STREAM_IS_OVER; + if (priv->sample_count>1) { + assert(priv->source->nb_real_streams); + priv->source->nb_real_streams--; + } + } + } + } + } + return GF_OK; + + case GF_ESI_INPUT_DESTROY: + if (priv->dsi) gf_free(priv->dsi); + if (ifce->decoder_config) { + gf_free(ifce->decoder_config); + ifce->decoder_config = NULL; + } + gf_free(priv); + ifce->input_udta = NULL; + return GF_OK; + default: + return GF_BAD_PARAM; + } +} + +static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFile *mp4, u32 track_num, u32 bifs_use_pes, Bool compute_max_size) +{ + GF_ESIMP4 *priv; + char *_lan; + GF_ESD *esd; + u64 avg_rate, duration; + s32 ref_count; + s64 mediaOffset; + + GF_SAFEALLOC(priv, GF_ESIMP4); + + priv->mp4 = mp4; + priv->track = track_num; + priv->mtype = gf_isom_get_media_type(priv->mp4, priv->track); + priv->mstype = gf_isom_get_media_subtype(priv->mp4, priv->track, 1); + priv->loop = source->real_time ? 1 : 0; + priv->sample_count = gf_isom_get_sample_count(mp4, track_num); + source->samples_count += priv->sample_count; + if (priv->sample_count>1) + source->nb_real_streams++; + + priv->source = source; + memset(ifce, 0, sizeof(GF_ESInterface)); + ifce->stream_id = gf_isom_get_track_id(mp4, track_num); + + esd = gf_media_map_esd(mp4, track_num); + + if (esd) { + ifce->stream_type = esd->decoderConfig->streamType; + ifce->object_type_indication = esd->decoderConfig->objectTypeIndication; + if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->dataLength) { + switch (esd->decoderConfig->objectTypeIndication) { + case GPAC_OTI_AUDIO_AAC_MPEG4: + case GPAC_OTI_AUDIO_AAC_MPEG2_MP: + case GPAC_OTI_AUDIO_AAC_MPEG2_LCP: + case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP: + case GPAC_OTI_VIDEO_MPEG4_PART2: + ifce->decoder_config = (char *)gf_malloc(sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength); + ifce->decoder_config_size = esd->decoderConfig->decoderSpecificInfo->dataLength; + memcpy(ifce->decoder_config, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); + break; + case GPAC_OTI_VIDEO_HEVC: + case GPAC_OTI_VIDEO_SHVC: + case GPAC_OTI_VIDEO_AVC: + case GPAC_OTI_VIDEO_SVC: + gf_isom_set_nalu_extract_mode(mp4, track_num, GF_ISOM_NALU_EXTRACT_LAYER_ONLY | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG | GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG | GF_ISOM_NALU_EXTRACT_VDRD_FLAG); + break; + case GPAC_OTI_SCENE_VTT_MP4: + ifce->decoder_config = (char *)gf_malloc(sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength); + ifce->decoder_config_size = esd->decoderConfig->decoderSpecificInfo->dataLength; + memcpy(ifce->decoder_config, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); + break; + } + } + gf_odf_desc_del((GF_Descriptor *)esd); + } + gf_isom_get_media_language(mp4, track_num, &_lan); + if (!_lan || !strcmp(_lan, "und")) { + ifce->lang = 0; + } else { + ifce->lang = GF_4CC(_lan[0],_lan[1],_lan[2],' '); + } + if (_lan) { + gf_free(_lan); + } + + ifce->timescale = gf_isom_get_media_timescale(mp4, track_num); + ifce->duration = gf_isom_get_media_timescale(mp4, track_num); + avg_rate = gf_isom_get_media_data_size(mp4, track_num); + avg_rate *= ifce->timescale * 8; + if (0!=(duration=gf_isom_get_media_duration(mp4, track_num))) + avg_rate /= duration; + + if (gf_isom_has_time_offset(mp4, track_num)) ifce->caps |= GF_ESI_SIGNAL_DTS; + + ifce->bit_rate = (u32) avg_rate; + ifce->duration = (Double) (s64) gf_isom_get_media_duration(mp4, track_num); + ifce->duration /= ifce->timescale; + + GF_SAFEALLOC(ifce->sl_config, GF_SLConfig); + ifce->sl_config->tag = GF_ODF_SLC_TAG; +// ifce->sl_config->predefined = 3; + ifce->sl_config->useAccessUnitStartFlag = 1; + ifce->sl_config->useAccessUnitEndFlag = 1; + ifce->sl_config->useRandomAccessPointFlag = 1; + ifce->sl_config->useTimestampsFlag = 1; + ifce->sl_config->timestampLength = 33; + ifce->sl_config->timestampResolution = ifce->timescale; + + /*test mode in which time stamps are 90khz and not coded but copied over from PES header*/ + if (bifs_use_pes==2) { + ifce->sl_config->timestampLength = 0; + ifce->sl_config->timestampResolution = 90000; + } + +#ifdef GPAC_DISABLE_ISOM_WRITE + fprintf(stderr, "Warning: GPAC was compiled without ISOM Write support, can't set SL Config!\n"); +#else + gf_isom_set_extraction_slc(mp4, track_num, 1, ifce->sl_config); +#endif + + ifce->input_ctrl = mp4_input_ctrl; + if (priv != ifce->input_udta) { + if (ifce->input_udta) + gf_free(ifce->input_udta); + ifce->input_udta = priv; + } + + + if (! gf_isom_get_edit_list_type(mp4, track_num, &mediaOffset)) { + priv->ts_offset = mediaOffset; + } + + ref_count = gf_isom_get_reference_count(mp4, track_num, GF_ISOM_REF_SCAL); + if (ref_count > 0) { + gf_isom_get_reference_ID(mp4, track_num, GF_ISOM_REF_SCAL, (u32) ref_count, &ifce->depends_on_stream); + } + else { + ifce->depends_on_stream = 0; + } + + if (compute_max_size) { + u32 i; + for (i=0; i < priv->sample_count; i++) { + u32 s = gf_isom_get_sample_size(mp4, track_num, i+1); + if (s>source->max_sample_size) source->max_sample_size = s; + } + } + +} + +#endif //GPAC_DISABLE_ISOM + + +#ifndef GPAC_DISABLE_SENG +static GF_Err seng_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) +{ + if (act_type==GF_ESI_INPUT_DESTROY) { + //TODO: free my data + if (ifce->input_udta) + gf_free(ifce->input_udta); + ifce->input_udta = NULL; + return GF_OK; + } + + return GF_OK; +} +#endif + + +#ifndef GPAC_DISABLE_STREAMING +typedef struct +{ + /*RTP channel*/ + GF_RTPChannel *rtp_ch; + + /*depacketizer*/ + GF_RTPDepacketizer *depacketizer; + + GF_ESIPacket pck; + + GF_ESInterface *ifce; + + Bool cat_dsi, is_264; + void *dsi_and_rap; + u32 avc_dsi_size; + + Bool use_carousel; + u32 au_sn; + + s64 ts_offset; + Bool rtcp_init; + M2TSSource *source; + + u32 min_dts_inc; + u64 prev_cts; + u64 prev_dts; +} GF_ESIRTP; + +static GF_Err rtp_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) +{ + u32 size, PayloadStart; + GF_Err e; + GF_RTPHeader hdr; + char buffer[8000]; + GF_ESIRTP *rtp = (GF_ESIRTP*)ifce->input_udta; + + if (!ifce->input_udta) return GF_BAD_PARAM; + + switch (act_type) { + case GF_ESI_INPUT_DATA_FLUSH: + /*flush rtcp channel*/ + while (1) { + Bool has_sr=0; + size = gf_rtp_read_rtcp(rtp->rtp_ch, buffer, 8000); + if (!size) break; + e = gf_rtp_decode_rtcp(rtp->rtp_ch, buffer, size, &has_sr); + + if (e == GF_EOS) ifce->caps |= GF_ESI_STREAM_IS_OVER; + + if (has_sr && !rtp->rtcp_init) { + Double time = rtp->rtp_ch->last_SR_NTP_sec; + time += ((Double)rtp->rtp_ch->last_SR_NTP_frac)/0xFFFFFFFF; + if (!rtp->source->last_ntp) { + rtp->source->last_ntp = time; + } + if (time >= rtp->source->last_ntp) { + time -= rtp->source->last_ntp; + } else { + time = 0; + } + rtp->ts_offset = rtp->rtp_ch->last_SR_rtp_time; + rtp->ts_offset -= (s64) (time * rtp->rtp_ch->TimeScale); + rtp->rtcp_init = 1; + } + } + /*flush rtp channel*/ + while (1) { + size = gf_rtp_read_rtp(rtp->rtp_ch, buffer, 8000); + if (!size) break; + e = gf_rtp_decode_rtp(rtp->rtp_ch, buffer, size, &hdr, &PayloadStart); + if (e) return e; + gf_rtp_depacketizer_process(rtp->depacketizer, &hdr, buffer + PayloadStart, size - PayloadStart); + } + return GF_OK; + case GF_ESI_INPUT_DESTROY: + gf_rtp_depacketizer_del(rtp->depacketizer); + if (rtp->dsi_and_rap) gf_free(rtp->dsi_and_rap); + gf_rtp_del(rtp->rtp_ch); + gf_free(rtp); + + if (ifce->decoder_config) { + gf_free(ifce->decoder_config); + ifce->decoder_config = NULL; + } + ifce->input_udta = NULL; + return GF_OK; + } + return GF_OK; +} + +static void rtp_sl_packet_cbk(void *udta, char *payload, u32 size, GF_SLHeader *hdr, GF_Err e) +{ + GF_ESIRTP *rtp = (GF_ESIRTP*)udta; + + /*sync not found yet, cannot start (since we don't support PCR discontinuities yet ...)*/ + if (!rtp->rtcp_init) return; + + /*try to compute a DTS*/ + if (hdr->accessUnitStartFlag && !hdr->decodingTimeStampFlag) { + if (!rtp->prev_cts) { + rtp->prev_cts = rtp->prev_dts = hdr->compositionTimeStamp; + } + + if (hdr->compositionTimeStamp > rtp->prev_cts) { + u32 diff = (u32) (hdr->compositionTimeStamp - rtp->prev_cts); + if (!rtp->min_dts_inc || (rtp->min_dts_inc > diff)) { + rtp->min_dts_inc = diff; + rtp->prev_dts = hdr->compositionTimeStamp - diff; + } + } + hdr->decodingTimeStampFlag = 1; + hdr->decodingTimeStamp = rtp->prev_dts + rtp->min_dts_inc; + rtp->prev_dts += rtp->min_dts_inc; + if (hdr->compositionTimeStamp < hdr->decodingTimeStamp) { + hdr->decodingTimeStamp = hdr->compositionTimeStamp; + } + } + + rtp->pck.data = payload; + rtp->pck.data_len = size; + rtp->pck.dts = hdr->decodingTimeStamp + rtp->ts_offset; + rtp->pck.cts = hdr->compositionTimeStamp + rtp->ts_offset; + rtp->pck.flags = 0; + if (hdr->compositionTimeStampFlag) rtp->pck.flags |= GF_ESI_DATA_HAS_CTS; + if (hdr->decodingTimeStampFlag) rtp->pck.flags |= GF_ESI_DATA_HAS_DTS; + if (hdr->randomAccessPointFlag) rtp->pck.flags |= GF_ESI_DATA_AU_RAP; + if (hdr->accessUnitStartFlag) rtp->pck.flags |= GF_ESI_DATA_AU_START; + if (hdr->accessUnitEndFlag) rtp->pck.flags |= GF_ESI_DATA_AU_END; + + if (rtp->use_carousel) { + if ((hdr->AU_sequenceNumber==rtp->au_sn) && hdr->randomAccessPointFlag) rtp->pck.flags |= GF_ESI_DATA_REPEAT; + rtp->au_sn = hdr->AU_sequenceNumber; + } + + if (rtp->is_264) { + if (!payload) return; + + /*send a NALU delim: copy over NAL ref idc*/ + if (hdr->accessUnitStartFlag) { + char sc[6]; + sc[0] = sc[1] = sc[2] = 0; + sc[3] = 1; + sc[4] = (payload[4] & 0x60) | GF_AVC_NALU_ACCESS_UNIT; + sc[5] = 0xF0 /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/; + + rtp->pck.data = sc; + rtp->pck.data_len = 6; + rtp->ifce->output_ctrl(rtp->ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &rtp->pck); + + rtp->pck.flags &= ~GF_ESI_DATA_AU_START; + + /*since we don't inspect the RTP content, we can only concatenate SPS and PPS indicated in SDP*/ + if (hdr->randomAccessPointFlag && rtp->dsi_and_rap) { + rtp->pck.data = rtp->dsi_and_rap; + rtp->pck.data_len = rtp->avc_dsi_size; + + rtp->ifce->output_ctrl(rtp->ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &rtp->pck); + } + + rtp->pck.data = payload; + rtp->pck.data_len = size; + } + + rtp->ifce->output_ctrl(rtp->ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &rtp->pck); + } else { + if (rtp->cat_dsi && hdr->randomAccessPointFlag && hdr->accessUnitStartFlag) { + if (rtp->dsi_and_rap) gf_free(rtp->dsi_and_rap); + rtp->pck.data_len = size + rtp->depacketizer->sl_map.configSize; + rtp->dsi_and_rap = gf_malloc(sizeof(char)*(rtp->pck.data_len)); + memcpy(rtp->dsi_and_rap, rtp->depacketizer->sl_map.config, rtp->depacketizer->sl_map.configSize); + memcpy((char *) rtp->dsi_and_rap + rtp->depacketizer->sl_map.configSize, payload, size); + rtp->pck.data = rtp->dsi_and_rap; + } + rtp->ifce->output_ctrl(rtp->ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &rtp->pck); + } +} + +static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInfo *sdp, M2TSSource *source) +{ + u32 i; + GF_Err e; + GF_X_Attribute*att; + GF_ESIRTP *rtp; + GF_RTPMap*map; + GF_SDPConnection *conn; + GF_RTSPTransport trans; + + /*check connection*/ + conn = sdp->c_connection; + if (!conn) conn = (GF_SDPConnection*)gf_list_get(media->Connections, 0); + + /*check payload type*/ + map = (GF_RTPMap*)gf_list_get(media->RTPMaps, 0); + GF_SAFEALLOC(rtp, GF_ESIRTP); + + memset(ifce, 0, sizeof(GF_ESInterface)); + rtp->rtp_ch = gf_rtp_new(); + i=0; + while ((att = (GF_X_Attribute*)gf_list_enum(media->Attributes, &i))) { + if (!stricmp(att->Name, "mpeg4-esid") && att->Value) ifce->stream_id = atoi(att->Value); + } + + memset(&trans, 0, sizeof(GF_RTSPTransport)); + trans.Profile = media->Profile; + trans.source = conn ? conn->host : sdp->o_address; + trans.IsUnicast = gf_sk_is_multicast_address(trans.source) ? 0 : 1; + if (!trans.IsUnicast) { + trans.port_first = media->PortNumber; + trans.port_last = media->PortNumber + 1; + trans.TTL = conn ? conn->TTL : 0; + } else { + trans.client_port_first = media->PortNumber; + trans.client_port_last = media->PortNumber + 1; + } + + if (gf_rtp_setup_transport(rtp->rtp_ch, &trans, NULL) != GF_OK) { + gf_rtp_del(rtp->rtp_ch); + fprintf(stderr, "Cannot initialize RTP transport\n"); + return; + } + /*setup depacketizer*/ + rtp->depacketizer = gf_rtp_depacketizer_new(media, rtp_sl_packet_cbk, rtp); + if (!rtp->depacketizer) { + gf_rtp_del(rtp->rtp_ch); + fprintf(stderr, "Cannot create RTP depacketizer\n"); + return; + } + /*setup channel*/ + gf_rtp_setup_payload(rtp->rtp_ch, map); + ifce->input_udta = rtp; + ifce->input_ctrl = rtp_input_ctrl; + rtp->ifce = ifce; + rtp->source = source; + + ifce->object_type_indication = rtp->depacketizer->sl_map.ObjectTypeIndication; + ifce->stream_type = rtp->depacketizer->sl_map.StreamType; + ifce->timescale = gf_rtp_get_clockrate(rtp->rtp_ch); + if (rtp->depacketizer->sl_map.config) { + switch (ifce->object_type_indication) { + case GPAC_OTI_VIDEO_MPEG4_PART2: + rtp->cat_dsi = 1; + break; + case GPAC_OTI_VIDEO_AVC: + case GPAC_OTI_VIDEO_SVC: + rtp->is_264 = 1; + rtp->depacketizer->flags |= GF_RTP_AVC_USE_ANNEX_B; + { +#ifndef GPAC_DISABLE_AV_PARSERS + GF_AVCConfig *avccfg = gf_odf_avc_cfg_read(rtp->depacketizer->sl_map.config, rtp->depacketizer->sl_map.configSize); + if (avccfg) { + GF_AVCConfigSlot *slc; + u32 i; + GF_BitStream *bs; + + bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); + for (i=0; isequenceParameterSets); i++) { + slc = gf_list_get(avccfg->sequenceParameterSets, i); + gf_bs_write_u32(bs, 1); + gf_bs_write_data(bs, slc->data, slc->size); + } + for (i=0; ipictureParameterSets); i++) { + slc = gf_list_get(avccfg->pictureParameterSets, i); + gf_bs_write_u32(bs, 1); + gf_bs_write_data(bs, slc->data, slc->size); + } + gf_bs_get_content(bs, (char **) &rtp->dsi_and_rap, &rtp->avc_dsi_size); + gf_bs_del(bs); + } + gf_odf_avc_cfg_del(avccfg); +#endif + } + break; + case GPAC_OTI_AUDIO_AAC_MPEG4: + ifce->decoder_config = gf_malloc(sizeof(char) * rtp->depacketizer->sl_map.configSize); + ifce->decoder_config_size = rtp->depacketizer->sl_map.configSize; + memcpy(ifce->decoder_config, rtp->depacketizer->sl_map.config, rtp->depacketizer->sl_map.configSize); + break; + } + } + if (rtp->depacketizer->sl_map.StreamStateIndication) { + rtp->use_carousel = 1; + rtp->au_sn=0; + } + + /*DTS signaling is only supported for MPEG-4 visual*/ + if (rtp->depacketizer->sl_map.DTSDeltaLength) ifce->caps |= GF_ESI_SIGNAL_DTS; + + gf_rtp_depacketizer_reset(rtp->depacketizer, 1); + e = gf_rtp_initialize(rtp->rtp_ch, 0x100000ul, 0, 0, 10, 200, NULL); + if (e!=GF_OK) { + gf_rtp_del(rtp->rtp_ch); + fprintf(stderr, "Cannot initialize RTP channel: %s\n", gf_error_to_string(e)); + return; + } + fprintf(stderr, "RTP interface initialized\n"); +} +#endif /*GPAC_DISABLE_STREAMING*/ + +#ifndef GPAC_DISABLE_SENG +static GF_Err void_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) +{ + return GF_OK; +} +#endif + +/*AAC import features*/ +#ifndef GPAC_DISABLE_PLAYER + +void *audio_prog = NULL; +static void SampleCallBack(void *calling_object, u16 ESID, char *data, u32 size, u64 ts); +#define DONT_USE_TERMINAL_MODULE_API +#include "../../modules/aac_in/aac_in.c" +AACReader *aac_reader = NULL; +u64 audio_discontinuity_offset = 0; + +/*create an OD codec and encode the descriptor*/ +static GF_Err encode_audio_desc(GF_ESD *esd, GF_SimpleDataDescriptor *audio_desc) +{ + GF_Err e; + GF_ODCodec *odc = gf_odf_codec_new(); + GF_ODUpdate *od_com = (GF_ODUpdate*)gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); + GF_ObjectDescriptor *od = (GF_ObjectDescriptor*)gf_odf_desc_new(GF_ODF_OD_TAG); + assert( esd ); + assert( audio_desc ); + gf_list_add(od->ESDescriptors, esd); + od->objectDescriptorID = AUDIO_DATA_ESID; + gf_list_add(od_com->objectDescriptors, od); + + e = gf_odf_codec_add_com(odc, (GF_ODCom*)od_com); + if (e) { + fprintf(stderr, "Audio input error add the command to be encoded\n"); + return e; + } + e = gf_odf_codec_encode(odc, 0); + if (e) { + fprintf(stderr, "Audio input error encoding the descriptor\n"); + return e; + } + e = gf_odf_codec_get_au(odc, &audio_desc->data, &audio_desc->size); + if (e) { + fprintf(stderr, "Audio input error getting the descriptor\n"); + return e; + } + e = gf_odf_com_del((GF_ODCom**)&od_com); + if (e) { + fprintf(stderr, "Audio input error deleting the command\n"); + return e; + } + gf_odf_codec_del(odc); + + return GF_OK; +} + +#endif + + +static void SampleCallBack(void *calling_object, u16 ESID, char *data, u32 size, u64 ts) +{ + u32 i; + //fprintf(stderr, "update: ESID=%d - size=%d - ts="LLD"\n", ESID, size, ts); + + if (calling_object) { + M2TSSource *source = (M2TSSource *)calling_object; + +#ifndef GPAC_DISABLE_PLAYER + if (ESID == AUDIO_DATA_ESID) { + if (audio_OD_stream_id != (u32)-1) { + /*this is the first time we get some audio data. Therefore we are sure we can retrieve the audio descriptor. Then we'll + send it by calling this callback recursively so that a player gets the audio descriptor before audio data. + Hack: the descriptor is carried thru the input_udta, you shall delete it*/ + GF_SimpleDataDescriptor *audio_desc = source->streams[audio_OD_stream_id].input_udta; + if (audio_desc && !audio_desc->data) /*intended for HTTP/AAC: an empty descriptor was set (vs already filled for RTP/UDP MP3)*/ + { + /*get the audio descriptor and encode it*/ + GF_ESD *esd = AAC_GetESD(aac_reader); + assert(esd->slConfig->timestampResolution); + esd->slConfig->useAccessUnitStartFlag = 1; + esd->slConfig->useAccessUnitEndFlag = 1; + esd->slConfig->useTimestampsFlag = 1; + esd->slConfig->timestampLength = 33; + /*audio stream, all samples are RAPs*/ + esd->slConfig->useRandomAccessPointFlag = 0; + esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1; + for (i=0; inb_streams; i++) { + if (source->streams[i].stream_id == AUDIO_DATA_ESID) { + GF_Err e; + source->streams[i].timescale = esd->slConfig->timestampResolution; + e = gf_m2ts_program_stream_update_ts_scale(&source->streams[i], esd->slConfig->timestampResolution); + assert(!e); + if (!source->streams[i].sl_config) source->streams[i].sl_config = (GF_SLConfig *)gf_odf_desc_new(GF_ODF_SLC_TAG); + memcpy(source->streams[i].sl_config, esd->slConfig, sizeof(GF_SLConfig)); + break; + } + } + esd->ESID = AUDIO_DATA_ESID; + assert(audio_OD_stream_id != (u32)-1); + encode_audio_desc(esd, audio_desc); + + /*build the ESI*/ + { + /*audio OD descriptor: rap=1 and vers_inc=0*/ + GF_SAFEALLOC(source->streams[audio_OD_stream_id].input_udta, GF_ESIStream); + ((GF_ESIStream*)source->streams[audio_OD_stream_id].input_udta)->rap = 1; + + /*we have the descriptor; now call this callback recursively so that a player gets the audio descriptor before audio data.*/ + source->repeat = 1; + SampleCallBack(source, AUDIO_OD_ESID, audio_desc->data, audio_desc->size, 0/*gf_m2ts_get_sys_clock(muxer)*/); + source->repeat = 0; + + /*clean*/ + gf_free(audio_desc->data); + gf_free(audio_desc); + gf_free(source->streams[audio_OD_stream_id].input_udta); + source->streams[audio_OD_stream_id].input_udta = NULL; + } + } + } + /*update the timescale if needed*/ + else if (!source->audio_configured) { + GF_ESD *esd = AAC_GetESD(aac_reader); + assert(esd->slConfig->timestampResolution); + for (i=0; inb_streams; i++) { + if (source->streams[i].stream_id == AUDIO_DATA_ESID) { + GF_Err e; + source->streams[i].timescale = esd->slConfig->timestampResolution; + source->streams[i].decoder_config = esd->decoderConfig->decoderSpecificInfo->data; + source->streams[i].decoder_config_size = esd->decoderConfig->decoderSpecificInfo->dataLength; + esd->decoderConfig->decoderSpecificInfo->data = NULL; + esd->decoderConfig->decoderSpecificInfo->dataLength = 0; + e = gf_m2ts_program_stream_update_ts_scale(&source->streams[i], esd->slConfig->timestampResolution); + if (!e) + source->audio_configured = 1; + break; + } + } + gf_odf_desc_del((GF_Descriptor *)esd); + } + + /*overwrite timing as it is flushed to 0 on discontinuities*/ + ts += audio_discontinuity_offset; + } +#endif + i=0; + while (inb_streams) { + if (source->streams[i].output_ctrl==NULL) { + fprintf(stderr, "MULTIPLEX NOT YET CREATED\n"); + return; + } + if (source->streams[i].stream_id == ESID) { + GF_ESIStream *priv = (GF_ESIStream *)source->streams[i].input_udta; + GF_ESIPacket pck; + memset(&pck, 0, sizeof(GF_ESIPacket)); + pck.data = data; + pck.data_len = size; + pck.flags |= GF_ESI_DATA_HAS_CTS; + pck.flags |= GF_ESI_DATA_HAS_DTS; + pck.flags |= GF_ESI_DATA_AU_START; + pck.flags |= GF_ESI_DATA_AU_END; + if (ts) pck.cts = pck.dts = ts; + + if (priv->rap) + pck.flags |= GF_ESI_DATA_AU_RAP; + if (source->repeat || !priv->vers_inc) { + pck.flags |= GF_ESI_DATA_REPEAT; + fprintf(stderr, "RAP carousel from scene engine sent: ESID=%d - size=%d - ts="LLD"\n", ESID, size, ts); + } else { + if (ESID != AUDIO_DATA_ESID && ESID != VIDEO_DATA_ESID) /*don't log A/V inputs*/ + fprintf(stderr, "Update from scene engine sent: ESID=%d - size=%d - ts="LLD"\n", ESID, size, ts); + } + source->streams[i].output_ctrl(&source->streams[i], GF_ESI_OUTPUT_DATA_DISPATCH, &pck); + return; + } + i++; + } + } + return; +} + +//static gf_seng_callback * SampleCallBack = &mySampleCallBack; + + +static volatile Bool run = 1; + +#ifndef GPAC_DISABLE_SENG +static GF_ESIStream * set_broadcast_params(M2TSSource *source, u16 esid, u32 period, u32 ts_delta, u16 aggregate_on_stream, Bool adjust_carousel_time, Bool force_rap, Bool aggregate_au, Bool discard_pending, Bool signal_rap, Bool signal_critical, Bool version_inc) +{ + u32 i=0; + GF_ESIStream *priv=NULL; + GF_ESInterface *esi=NULL; + + /*locate our stream*/ + if (esid) { + while (inb_streams) { + if (source->streams[i].stream_id == esid) { + priv = (GF_ESIStream *)source->streams[i].input_udta; + esi = &source->streams[i]; + break; + } + else { + i++; + } + } + /*TODO: stream not found*/ + } + + /*TODO - set/reset the ESID for the parsers*/ + if (!priv) return NULL; + + /*TODO - if discard is set, abort current carousel*/ + if (discard_pending) { + } + + /*remember RAP flag*/ + priv->rap = signal_rap; + priv->critical = signal_critical; + priv->vers_inc = version_inc; + + priv->ts_delta = ts_delta; + priv->adjust_carousel_time = adjust_carousel_time; + + /*change stream aggregation mode*/ + if ((aggregate_on_stream != (u16)-1) && (priv->aggregate_on_stream != aggregate_on_stream)) { + gf_seng_enable_aggregation(source->seng, esid, aggregate_on_stream); + priv->aggregate_on_stream = aggregate_on_stream; + } + /*change stream aggregation mode*/ + if (priv->aggregate_on_stream==esi->stream_id) { + if (priv->aggregate_on_stream && (period!=(u32)-1) && (esi->repeat_rate != period)) { + esi->repeat_rate = period; + } + } else { + esi->repeat_rate = 0; + } + return priv; +} +#endif + +#ifndef GPAC_DISABLE_SENG + +static u32 seng_output(void *param) +{ + GF_Err e; + u64 last_src_modif, mod_time; + M2TSSource *source = (M2TSSource *)param; + GF_SceneEngine *seng = source->seng; + GF_SimpleDataDescriptor *audio_desc; + Bool update_context=0; + Bool force_rap, adjust_carousel_time, discard_pending, signal_rap, signal_critical, version_inc, aggregate_au; + u32 period, ts_delta; + u16 es_id, aggregate_on_stream; + e = GF_OK; + gf_sleep(2000); /*TODO: events instead? What are we waiting for?*/ + gf_seng_encode_context(seng, SampleCallBack); + + last_src_modif = source->bifs_src_name ? gf_file_modification_time(source->bifs_src_name) : 0; + + /*send the audio descriptor*/ + if (source->mpeg4_signaling==GF_M2TS_MPEG4_SIGNALING_FULL && audio_OD_stream_id!=(u32)-1) { + audio_desc = source->streams[audio_OD_stream_id].input_udta; + if (audio_desc && audio_desc->data) /*RTP/UDP + MP3 case*/ + { + assert(audio_OD_stream_id != (u32)-1); + assert(!aac_reader); /*incompatible with AAC*/ + source->repeat = 1; + SampleCallBack(source, AUDIO_OD_ESID, audio_desc->data, audio_desc->size, 0/*gf_m2ts_get_sys_clock(muxer)*/); + source->repeat = 0; + gf_free(audio_desc->data); + gf_free(audio_desc); + source->streams[audio_OD_stream_id].input_udta = NULL; + } + } + + while (run) { + if (!gf_prompt_has_input()) { + if (source->bifs_src_name) { + mod_time = gf_file_modification_time(source->bifs_src_name); + if (mod_time != last_src_modif) { + FILE *srcf; + char flag_buf[201], *flag; + fprintf(stderr, "Update file modified - processing\n"); + last_src_modif = mod_time; + + srcf = gf_fopen(source->bifs_src_name, "rt"); + if (!srcf) continue; + + /*checks if we have a broadcast config*/ + if (!fgets(flag_buf, 200, srcf)) + flag_buf[0] = '\0'; + gf_fclose(srcf); + + aggregate_au = force_rap = adjust_carousel_time = discard_pending = signal_rap = signal_critical = 0; + version_inc = 1; + period = -1; + aggregate_on_stream = -1; + ts_delta = 0; + es_id = 0; + + /*find our keyword*/ + flag = strstr(flag_buf, "gpac_broadcast_config "); + if (flag) { + flag += strlen("gpac_broadcast_config "); + /*move to next word*/ + while (flag && (flag[0]==' ')) flag++; + + while (1) { + char *sep = strchr(flag, ' '); + if (sep) sep[0] = 0; + if (!strnicmp(flag, "esid=", 5)) { + /*ESID on which the update is applied*/ + es_id = atoi(flag+5); + } else if (!strnicmp(flag, "period=", 7)) { + /*TODO: target period carousel for ESID ??? (ESID/carousel)*/ + period = atoi(flag+7); + } else if (!strnicmp(flag, "ts=", 3)) { + /*TODO: */ + ts_delta = atoi(flag+3); + } else if (!strnicmp(flag, "carousel=", 9)) { + /*TODO: why? => sends the update on carousel id specified by this argument*/ + aggregate_on_stream = atoi(flag+9); + } else if (!strnicmp(flag, "restamp=", 8)) { + /*CTS is updated when carouselled*/ + adjust_carousel_time = atoi(flag+8); + } else if (!strnicmp(flag, "discard=", 8)) { + /*when we receive several updates during a single carousel period, this attribute specifies whether the current update discard pending ones*/ + discard_pending = atoi(flag+8); + } else if (!strnicmp(flag, "aggregate=", 10)) { + /*Boolean*/ + aggregate_au = atoi(flag+10); + } else if (!strnicmp(flag, "force_rap=", 10)) { + /*TODO: */ + force_rap = atoi(flag+10); + } else if (!strnicmp(flag, "rap=", 4)) { + /*TODO: */ + signal_rap = atoi(flag+4); + } else if (!strnicmp(flag, "critical=", 9)) { + /*TODO: */ + signal_critical = atoi(flag+9); + } else if (!strnicmp(flag, "vers_inc=", 9)) { + /*Boolean to increment m2ts section version number*/ + version_inc = atoi(flag+9); + } + if (sep) { + sep[0] = ' '; + flag = sep+1; + } else { + break; + } + } + + set_broadcast_params(source, es_id, period, ts_delta, aggregate_on_stream, adjust_carousel_time, force_rap, aggregate_au, discard_pending, signal_rap, signal_critical, version_inc); + } + + e = gf_seng_encode_from_file(seng, es_id, aggregate_au ? 0 : 1, source->bifs_src_name, SampleCallBack); + if (e) { + fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); + } else + gf_seng_aggregate_context(seng, 0); + + update_context=1; + + + + } + } + if (update_context) { + source->repeat = 1; + e = gf_seng_encode_context(seng, SampleCallBack); + source->repeat = 0; + update_context = 0; + } + + gf_sleep(10); + } else { /*gf_prompt_has_input()*/ + char c = gf_prompt_get_char(); + switch (c) { + case 'u': + { + GF_Err e; + char szCom[8192]; + fprintf(stderr, "Enter command to send:\n"); + fflush(stdin); + szCom[0] = 0; + if (1 > scanf("%[^\t\n]", szCom)) { + fprintf(stderr, "No command has been properly entered, aborting.\n"); + break; + } + e = gf_seng_encode_from_string(seng, 0, 0, szCom, SampleCallBack); + if (e) { + fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); + } + update_context=1; + } + break; + case 'p': + { + char rad[GF_MAX_PATH]; + fprintf(stderr, "Enter output file name - \"std\" for stderr: "); + if (1 > scanf("%s", rad)) { + fprintf(stderr, "No outfile name has been entered, aborting.\n"); + break; + } + e = gf_seng_save_context(seng, !strcmp(rad, "std") ? NULL : rad); + fprintf(stderr, "Dump done (%s)\n", gf_error_to_string(e)); + } + break; + case 'q': + { + run = 0; + } + } + e = GF_OK; + } + } + + + return e ? 1 : 0; +} + +void fill_seng_es_ifce(GF_ESInterface *ifce, u32 i, GF_SceneEngine *seng, u32 period) +{ + GF_Err e = GF_OK; + u32 len; + GF_ESIStream *stream; + char *config_buffer = NULL; + + memset(ifce, 0, sizeof(GF_ESInterface)); + e = gf_seng_get_stream_config(seng, i, (u16*) &(ifce->stream_id), &config_buffer, &len, (u32*) &(ifce->stream_type), (u32*) &(ifce->object_type_indication), &(ifce->timescale)); + if (e) { + fprintf(stderr, "Cannot set the stream config for stream %d to %d: %s\n", ifce->stream_id, period, gf_error_to_string(e)); + } + + ifce->repeat_rate = period; + GF_SAFEALLOC(stream, GF_ESIStream); + memset(stream, 0, sizeof(GF_ESIStream)); + stream->rap = 1; + if (ifce->input_udta) + gf_free(ifce->input_udta); + ifce->input_udta = stream; + + //fprintf(stderr, "Caroussel period: %d\n", period); +// e = gf_seng_set_carousel_time(seng, ifce->stream_id, period); + if (e) { + fprintf(stderr, "Cannot set carousel time on stream %d to %d: %s\n", ifce->stream_id, period, gf_error_to_string(e)); + } + ifce->input_ctrl = seng_input_ctrl; + +} +#endif + +static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mpeg4_signaling, char *update, char *audio_input_ip, u16 audio_input_port, char *video_buffer, Bool force_real_time, u32 bifs_use_pes, const char *temi_url, Bool compute_max_size, Bool insert_ntp) +{ +#ifndef GPAC_DISABLE_STREAMING + GF_SDPInfo *sdp; +#endif + s64 min_offset = 0; + + memset(source, 0, sizeof(M2TSSource)); + source->mpeg4_signaling = mpeg4_signaling; + + /*open ISO file*/ +#ifndef GPAC_DISABLE_ISOM + if (gf_isom_probe_file(src)) { + u32 i; + u32 nb_tracks; + Bool has_bifs_od = 0; + u32 first_audio = 0; + u32 first_other = 0; + source->mp4 = gf_isom_open(src, GF_ISOM_OPEN_READ, 0); + source->nb_streams = 0; + source->real_time = force_real_time; + /*on MPEG-2 TS, carry 3GPP timed text as MPEG-4 Part17*/ + gf_isom_text_set_streaming_mode(source->mp4, 1); + nb_tracks = gf_isom_get_track_count(source->mp4); + + for (i=0; imp4, i+1) == GF_ISOM_MEDIA_HINT) + continue; + + fill_isom_es_ifce(source, &source->streams[i], source->mp4, i+1, bifs_use_pes, compute_max_size); + if (min_offset > ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset) + min_offset = ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset; + + switch(source->streams[i].stream_type) { + case GF_STREAM_OD: + has_bifs_od = 1; + source->streams[i].repeat_rate = carousel_rate; + break; + case GF_STREAM_SCENE: + has_bifs_od = 1; + source->streams[i].repeat_rate = carousel_rate; + break; + case GF_STREAM_VISUAL: + /*turn on image repeat*/ + switch (source->streams[i].object_type_indication) { + case GPAC_OTI_IMAGE_JPEG: + case GPAC_OTI_IMAGE_PNG: + ((GF_ESIMP4 *)source->streams[i].input_udta)->image_repeat_ms = carousel_rate; + break; + default: + check_deps = 1; + if (gf_isom_get_sample_count(source->mp4, i+1)>1) { + /*get first visual stream as PCR*/ + if (!source->pcr_idx) { + source->pcr_idx = i+1; + if (temi_url) { + ((GF_ESIMP4 *)source->streams[i].input_udta)->insert_temi = GF_TRUE; + if (insert_ntp) + ((GF_ESIMP4 *)source->streams[i].input_udta)->insert_ntp = GF_TRUE; + if (strcmp(temi_url, "NOTEMIURL")) + ((GF_ESIMP4 *)source->streams[i].input_udta)->temi_url = temi_url; + } + } + } + break; + } + break; + case GF_STREAM_AUDIO: + if (!first_audio) first_audio = i+1; + check_deps = 1; + break; + default: + /*log not supported stream type: %s*/ + break; + } + source->nb_streams++; + if (gf_isom_get_sample_count(source->mp4, i+1)>1) first_other = i+1; + + if (check_deps) { + u32 k; + Bool found_dep = 0; + for (k=0; kmp4, k+1) != GF_ISOM_MEDIA_OD) + continue; + + /*this stream is not refered to by any OD, send as regular PES*/ + if (gf_isom_has_track_reference(source->mp4, k+1, GF_ISOM_REF_OD, gf_isom_get_track_id(source->mp4, i+1) )==1) { + found_dep = 1; + break; + } + } + if (!found_dep) { + source->streams[i].caps |= GF_ESI_STREAM_WITHOUT_MPEG4_SYSTEMS; + } + } + } + if (has_bifs_od && !source->mpeg4_signaling) source->mpeg4_signaling = GF_M2TS_MPEG4_SIGNALING_FULL; + + /*if no visual PCR found, use first audio*/ + if (!source->pcr_idx) source->pcr_idx = first_audio; + if (!source->pcr_idx) source->pcr_idx = first_other; + if (source->pcr_idx) { + GF_ESIMP4 *priv; + source->pcr_idx-=1; + priv = source->streams[source->pcr_idx].input_udta; + gf_isom_set_default_sync_track(source->mp4, priv->track); + } + + if (min_offset < 0) { + for (i=0; inb_streams; i++) { + ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset += -min_offset; + } + } + + source->iod = gf_isom_get_root_od(source->mp4); + if (source->iod) { + GF_ObjectDescriptor*iod = (GF_ObjectDescriptor*)source->iod; + if (gf_list_count( ((GF_ObjectDescriptor*)source->iod)->ESDescriptors) == 0) { + gf_odf_desc_del(source->iod); + source->iod = NULL; + } else { + fprintf(stderr, "IOD found for program %s\n", src); + + /*if using 4over2, get rid of OD tracks*/ + if (source->mpeg4_signaling==GF_M2TS_MPEG4_SIGNALING_SCENE) { + for (i=0; iESDescriptors); i++) { + u32 track_num, k; + GF_M2TSDescriptor *oddesc; + GF_ISOSample *sample; + GF_ESD *esd = gf_list_get(iod->ESDescriptors, i); + if (esd->decoderConfig->streamType!=GF_STREAM_OD) continue; + track_num = gf_isom_get_track_by_id(source->mp4, esd->ESID); + if (gf_isom_get_sample_count(source->mp4, track_num)>1) continue; + + sample = gf_isom_get_sample(source->mp4, track_num, 1, NULL); + if (sample->dataLength >= 255-2) { + gf_isom_sample_del(&sample); + continue; + } + /*rewrite ESD dependencies*/ + for (k=0; kESDescriptors); k++) { + GF_ESD *dep_esd = gf_list_get(iod->ESDescriptors, k); + if (dep_esd->dependsOnESID==esd->ESID) dep_esd->dependsOnESID = esd->dependsOnESID; + } + + for (k=0; knb_streams; k++) { + if (source->streams[k].stream_id==esd->ESID) { + source->streams[k].stream_type = 0; + break; + } + } + + if (!source->od_updates) source->od_updates = gf_list_new(); + GF_SAFEALLOC(oddesc, GF_M2TSDescriptor); + oddesc->data_len = sample->dataLength; + oddesc->data = sample->data; + oddesc->tag = GF_M2TS_MPEG4_ODUPDATE_DESCRIPTOR; + sample->data = NULL; + gf_isom_sample_del(&sample); + gf_list_add(source->od_updates, oddesc); + + gf_list_rem(iod->ESDescriptors, i); + i--; + gf_odf_desc_del((GF_Descriptor *) esd); + source->samples_count--; + } + } + + } + } + return 1; + } +#endif + + +#ifndef GPAC_DISABLE_STREAMING + /*open SDP file*/ + if (strstr(src, ".sdp")) { + GF_X_Attribute *att; + char *sdp_buf; + u32 sdp_size, i; + GF_Err e; + FILE *_sdp = gf_fopen(src, "rt"); + if (!_sdp) { + fprintf(stderr, "Error opening %s - no such file\n", src); + return 0; + } + gf_fseek(_sdp, 0, SEEK_END); + sdp_size = (u32)gf_ftell(_sdp); + gf_fseek(_sdp, 0, SEEK_SET); + sdp_buf = (char*)gf_malloc(sizeof(char)*sdp_size); + memset(sdp_buf, 0, sizeof(char)*sdp_size); + sdp_size = (u32) fread(sdp_buf, 1, sdp_size, _sdp); + gf_fclose(_sdp); + + sdp = gf_sdp_info_new(); + e = gf_sdp_info_parse(sdp, sdp_buf, sdp_size); + gf_free(sdp_buf); + if (e) { + fprintf(stderr, "Error opening %s : %s\n", src, gf_error_to_string(e)); + gf_sdp_info_del(sdp); + return 0; + } + + i=0; + while ((att = (GF_X_Attribute*)gf_list_enum(sdp->Attributes, &i))) { + char buf[2000]; + u32 size; + char *buf64; + u32 size64; + char *iod_str; + if (strcmp(att->Name, "mpeg4-iod") ) continue; + iod_str = att->Value + 1; + if (strnicmp(iod_str, "data:application/mpeg4-iod;base64", strlen("data:application/mpeg4-iod;base64"))) continue; + + buf64 = strstr(iod_str, ","); + if (!buf64) break; + buf64 += 1; + size64 = (u32) strlen(buf64) - 1; + size = gf_base64_decode(buf64, size64, buf, 2000); + + gf_odf_desc_read(buf, size, &source->iod); + break; + } + + source->nb_streams = gf_list_count(sdp->media_desc); + for (i=0; inb_streams; i++) { + GF_SDPMedia *media = gf_list_get(sdp->media_desc, i); + fill_rtp_es_ifce(&source->streams[i], media, sdp, source); + switch(source->streams[i].stream_type) { + case GF_STREAM_OD: + case GF_STREAM_SCENE: + source->mpeg4_signaling = GF_M2TS_MPEG4_SIGNALING_FULL; + source->streams[i].repeat_rate = carousel_rate; + break; + } + if (!source->pcr_idx && (source->streams[i].stream_type == GF_STREAM_VISUAL)) { + source->pcr_idx = i+1; + } + } + + if (source->pcr_idx) source->pcr_idx-=1; + gf_sdp_info_del(sdp); + + return 2; + } else +#endif /*GPAC_DISABLE_STREAMING*/ + +#ifndef GPAC_DISABLE_SENG + if (strstr(src, ".bt")) //open .bt file + { + u32 i; + u32 load_type=0; + source->seng = gf_seng_init(source, src, load_type, NULL, (load_type == GF_SM_LOAD_DIMS) ? 1 : 0); + if (!source->seng) { + fprintf(stderr, "Cannot create scene engine\n"); + exit(1); + } + else { + fprintf(stderr, "Scene engine created.\n"); + } + assert( source ); + assert( source->seng); + source->iod = gf_seng_get_iod(source->seng); + if (! source->iod) { + fprintf(stderr, __FILE__": No IOD\n"); + } + + source->nb_streams = gf_seng_get_stream_count(source->seng); + source->rate = carousel_rate; + source->mpeg4_signaling = GF_M2TS_MPEG4_SIGNALING_FULL; + + for (i=0; inb_streams; i++) { + fill_seng_es_ifce(&source->streams[i], i, source->seng, source->rate); + //fprintf(stderr, "Fill interface\n"); + if (!source->pcr_idx && (source->streams[i].stream_type == GF_STREAM_AUDIO)) { + source->pcr_idx = i+1; + } + } + + /*when an audio input is present, declare it and store OD + ESD_U*/ + if (audio_input_ip) { + /*add the audio program*/ + source->pcr_idx = source->nb_streams; + source->streams[source->nb_streams].stream_type = GF_STREAM_AUDIO; + /*hack: http urls are not decomposed therefore audio_input_port remains null*/ + if (audio_input_port) { /*UDP/RTP*/ + source->streams[source->nb_streams].object_type_indication = GPAC_OTI_AUDIO_MPEG1; + } else { /*HTTP*/ + aac_reader->oti = source->streams[source->nb_streams].object_type_indication = GPAC_OTI_AUDIO_AAC_MPEG4; + } + source->streams[source->nb_streams].input_ctrl = void_input_ctrl; + source->streams[source->nb_streams].stream_id = AUDIO_DATA_ESID; + source->streams[source->nb_streams].timescale = 1000; + + GF_SAFEALLOC(source->streams[source->nb_streams].input_udta, GF_ESIStream); + ((GF_ESIStream*)source->streams[source->nb_streams].input_udta)->vers_inc = 1; /*increment version number at every audio update*/ + assert( source ); + //assert( source->iod); + if (source->iod && ((source->iod->tag!=GF_ODF_IOD_TAG) || (mpeg4_signaling != GF_M2TS_MPEG4_SIGNALING_SCENE))) { + /*create the descriptor*/ + GF_ESD *esd; + GF_SimpleDataDescriptor *audio_desc; + GF_SAFEALLOC(audio_desc, GF_SimpleDataDescriptor); + if (audio_input_port) { /*UDP/RTP*/ + esd = gf_odf_desc_esd_new(0); + esd->decoderConfig->streamType = source->streams[source->nb_streams].stream_type; + esd->decoderConfig->objectTypeIndication = source->streams[source->nb_streams].object_type_indication; + } else { /*HTTP*/ + esd = AAC_GetESD(aac_reader); /*in case of AAC, we have to wait the first ADTS chunk*/ + } + assert( esd ); + esd->ESID = source->streams[source->nb_streams].stream_id; + if (esd->slConfig->timestampResolution) /*in case of AAC, we have to wait the first ADTS chunk*/ + encode_audio_desc(esd, audio_desc); + else + gf_odf_desc_del((GF_Descriptor *)esd); + + /*find the audio OD stream and attach its descriptor*/ + for (i=0; inb_streams; i++) { + if (source->streams[i].stream_id == AUDIO_OD_ESID) { + if (source->streams[i].input_udta) + gf_free(source->streams[i].input_udta); + source->streams[i].input_udta = (void*)audio_desc; /*Hack: the real input_udta type (for our SampleCallBack function) is GF_ESIStream*/ + audio_OD_stream_id = i; + break; + } + } + if (audio_OD_stream_id == (u32)-1) { + fprintf(stderr, "Error: could not find an audio OD stream with ESID=100 in '%s'\n", src); + return 0; + } + } else { + source->mpeg4_signaling = GF_M2TS_MPEG4_SIGNALING_SCENE; + } + source->nb_streams++; + } + + /*when an audio input is present, declare it and store OD + ESD_U*/ + if (video_buffer) { + /*add the video program*/ + source->streams[source->nb_streams].stream_type = GF_STREAM_VISUAL; + source->streams[source->nb_streams].object_type_indication = GPAC_OTI_VIDEO_AVC; + source->streams[source->nb_streams].input_ctrl = void_input_ctrl; + source->streams[source->nb_streams].stream_id = VIDEO_DATA_ESID; + source->streams[source->nb_streams].timescale = 1000; + + GF_SAFEALLOC(source->streams[source->nb_streams].input_udta, GF_ESIStream); + ((GF_ESIStream*)source->streams[source->nb_streams].input_udta)->vers_inc = 1; /*increment version number at every video update*/ + assert(source); + + if (source->iod && ((source->iod->tag!=GF_ODF_IOD_TAG) || (mpeg4_signaling != GF_M2TS_MPEG4_SIGNALING_SCENE))) { + assert(0); /*TODO*/ +#if 0 + /*create the descriptor*/ + GF_ESD *esd; + GF_SimpleDataDescriptor *video_desc; + GF_SAFEALLOC(video_desc, GF_SimpleDataDescriptor); + esd = gf_odf_desc_esd_new(0); + esd->decoderConfig->streamType = source->streams[source->nb_streams].stream_type; + esd->decoderConfig->objectTypeIndication = source->streams[source->nb_streams].object_type_indication; + esd->ESID = source->streams[source->nb_streams].stream_id; + + /*find the audio OD stream and attach its descriptor*/ + for (i=0; inb_streams; i++) { + if (source->streams[i].stream_id == 103/*TODO: VIDEO_OD_ESID*/) { + if (source->streams[i].input_udta) + gf_free(source->streams[i].input_udta); + source->streams[i].input_udta = (void*)video_desc; + audio_OD_stream_id = i; + break; + } + } + if (audio_OD_stream_id == (u32)-1) { + fprintf(stderr, "Error: could not find an audio OD stream with ESID=100 in '%s'\n", src); + return 0; + } +#endif + } else { + assert (source->mpeg4_signaling == GF_M2TS_MPEG4_SIGNALING_SCENE); + } + + source->nb_streams++; + } + + if (!source->pcr_idx) source->pcr_idx=1; + source->th = gf_th_new("Carousel"); + source->bifs_src_name = update; + gf_th_run(source->th, seng_output, source); + return 1; + } else +#endif + { + FILE *f = gf_fopen(src, "rt"); + if (f) { + gf_fclose(f); + fprintf(stderr, "Error opening %s - not a supported input media, skipping.\n", src); + } else { + fprintf(stderr, "Error opening %s - no such file.\n", src); + } + return 0; + } +} + +#ifdef GPAC_MEMORY_TRACKING +static Bool enable_mem_tracker = GF_FALSE; +#endif + +/*macro to keep retro compatibility with '=' and spaces in parse_args*/ +#define CHECK_PARAM(param) (!strnicmp(arg, param, strlen(param)) \ + && ( ((arg[strlen(param)] == '=') && (next_arg = arg+strlen(param)+1)) \ + || ((strlen(arg) == strlen(param)) && ++i && (i 150) { + fprintf(stderr, "URLs longer than 150 bytes are not currently supported\n"); + return GF_NOT_SUPPORTED; + } + } + } + else if (CHECK_PARAM("-temi-delay")) { + temi_url_insertion_delay = atoi(next_arg); + } else if (CHECK_PARAM("-temi-offset")) { + temi_offset = atoi(next_arg); + } else if (!stricmp(arg, "-temi-noloop")) { + temi_disable_loop = 1; + } else if (!stricmp(arg, "-insert-ntp")) { + insert_ntp = GF_TRUE; + } + else if (CHECK_PARAM("-dst-udp")) { + char *sep = strchr(next_arg, ':'); + dst_found = 1; + *real_time=1; + if (sep) { + *output_port = atoi(sep+1); + sep[0]=0; + *udp_out = gf_strdup(next_arg); + sep[0]=':'; + } else { + *udp_out = gf_strdup(next_arg); + } + } + else if (CHECK_PARAM("-dst-rtp")) { + char *sep = strchr(next_arg, ':'); + dst_found = 1; + *real_time=1; + if (sep) { + *output_port = atoi(sep+1); + sep[0]=0; + *rtp_out = gf_strdup(next_arg); + sep[0]=':'; + } else { + *rtp_out = gf_strdup(next_arg); + } + } else if (CHECK_PARAM("-src")) { //second pass arguments + } else if (CHECK_PARAM("-prog")) { //second pass arguments + } + else { + error_msg = "unknown option"; + goto error; + } + } + if (*real_time) force_real_time = 1; + rate_found = 1; + + /*second pass: other*/ + for (i=1; i=0) gf_m2ts_mux_set_initial_pcr(muxer, (u64) pcr_init_val); + gf_m2ts_mux_set_pcr_max_interval(muxer, pcr_ms); + + if (ts_out != NULL) { + if (segment_duration) { + strcpy(segment_prefix, ts_out); + if (segment_dir) { + if (strchr("\\/", segment_name[strlen(segment_name)-1])) { + sprintf(segment_name, "%s%s_%d.ts", segment_dir, segment_prefix, segment_index); + } else { + sprintf(segment_name, "%s/%s_%d.ts", segment_dir, segment_prefix, segment_index); + } + } else { + sprintf(segment_name, "%s_%d.ts", segment_prefix, segment_index); + } + ts_out = gf_strdup(segment_name); + if (!segment_manifest) { + sprintf(segment_manifest_default, "%s.m3u8", segment_prefix); + segment_manifest = segment_manifest_default; + } + //write_manifest(segment_manifest, segment_dir, segment_duration, segment_prefix, segment_http_prefix, segment_index, 0, 0); + } + if (!strcmp(ts_out, "stdout") || !strcmp(ts_out, "-") ) { + ts_output_file = stdout; + is_stdout = GF_TRUE; + } else { + ts_output_file = gf_fopen(ts_out, "wb"); + is_stdout = GF_FALSE; + } + if (!ts_output_file) { + fprintf(stderr, "Error opening %s\n", ts_out); + goto exit; + } + } + if (udp_out != NULL) { + ts_output_udp_sk = gf_sk_new(GF_SOCK_TYPE_UDP); + if (gf_sk_is_multicast_address((char *)udp_out)) { + e = gf_sk_setup_multicast(ts_output_udp_sk, (char *)udp_out, output_port, ttl, 0, (char *) ip_ifce); + } else { + e = gf_sk_bind(ts_output_udp_sk, ip_ifce, output_port, (char *)udp_out, output_port, GF_SOCK_REUSE_PORT); + } + if (e) { + fprintf(stderr, "Error initializing UDP socket: %s\n", gf_error_to_string(e)); + goto exit; + } + } +#ifndef GPAC_DISABLE_STREAMING + if (rtp_out != NULL) { + ts_output_rtp = gf_rtp_new(); + gf_rtp_set_ports(ts_output_rtp, output_port); + memset(&tr, 0, sizeof(GF_RTSPTransport)); + tr.IsUnicast = gf_sk_is_multicast_address((char *)rtp_out) ? 0 : 1; + tr.Profile="RTP/AVP"; + tr.destination = (char *)rtp_out; + tr.source = "0.0.0.0"; + tr.IsRecord = 0; + tr.Append = 0; + tr.SSRC = rand(); + tr.port_first = output_port; + tr.port_last = output_port+1; + if (tr.IsUnicast) { + tr.client_port_first = output_port; + tr.client_port_last = output_port+1; + } else { + tr.source = (char *)rtp_out; + tr.TTL = ttl; + } + e = gf_rtp_setup_transport(ts_output_rtp, &tr, (char *)ts_out); + if (e != GF_OK) { + fprintf(stderr, "Cannot setup RTP transport info : %s\n", gf_error_to_string(e)); + goto exit; + } + e = gf_rtp_initialize(ts_output_rtp, 0, 1, 1500, 0, 0, (char *) ip_ifce); + if (e != GF_OK) { + fprintf(stderr, "Cannot initialize RTP sockets : %s\n", gf_error_to_string(e)); + goto exit; + } + memset(&hdr, 0, sizeof(GF_RTPHeader)); + hdr.Version = 2; + hdr.PayloadType = 33; /*MP2T*/ + hdr.SSRC = tr.SSRC; + hdr.Marker = 0; + } +#endif /*GPAC_DISABLE_STREAMING*/ + + /************************************/ + /* create streaming audio input */ + /************************************/ + if (audio_input_ip) + switch(audio_input_type) { + case GF_MP42TS_UDP: + audio_input_udp_sk = gf_sk_new(GF_SOCK_TYPE_UDP); + if (gf_sk_is_multicast_address((char *)audio_input_ip)) { + e = gf_sk_setup_multicast(audio_input_udp_sk, (char *)audio_input_ip, audio_input_port, 32, 0, NULL); + } else { + e = gf_sk_bind(audio_input_udp_sk, NULL, audio_input_port, (char *)audio_input_ip, audio_input_port, GF_SOCK_REUSE_PORT); + } + if (e) { + fprintf(stderr, "Error initializing UDP socket for %s:%d : %s\n", audio_input_ip, audio_input_port, gf_error_to_string(e)); + goto exit; + } + gf_sk_set_buffer_size(audio_input_udp_sk, 0, UDP_BUFFER_SIZE); + gf_sk_set_block_mode(audio_input_udp_sk, 0); + + /*allocate data buffer*/ + audio_input_buffer = (char*)gf_malloc(audio_input_buffer_length); + assert(audio_input_buffer); + break; + case GF_MP42TS_RTP: + /*TODO: not implemented*/ + assert(0); + break; +#ifndef GPAC_DISABLE_PLAYER + case GF_MP42TS_HTTP: + audio_prog = (void*)&sources[nb_sources-1]; + aac_download_file(aac_reader, audio_input_ip); + break; +#endif + case GF_MP42TS_FILE: + assert(0); /*audio live input is restricted to realtime/streaming*/ + break; + default: + assert(0); + } + + if (!nb_sources) { + fprintf(stderr, "No program to mux, quitting.\n"); + } + + for (i=0; iiod = sources[i].iod; + if (sources[i].od_updates) { + program->loop_descriptors = sources[i].od_updates; + sources[i].od_updates = NULL; + } + } else { + program = gf_m2ts_mux_program_find(muxer, sources[i].ID); + } + if (!program) continue; + + for (j=0; jstart_pes_at_rap = 1; + } + + cur_pid += sources[i].nb_streams; + while (cur_pid % 10) + cur_pid ++; + + if (sources[i].program_name[0] || sources[i].provider_name[0] ) gf_m2ts_mux_program_set_name(program, sources[i].program_name, sources[i].provider_name); + } + muxer->flush_pes_at_rap = (split_rap == 2) ? GF_TRUE : GF_FALSE; + + if (sdt_refresh_rate) { + gf_m2ts_mux_enable_sdt(muxer, sdt_refresh_rate); + } + gf_m2ts_mux_update_config(muxer, 1); + + if (nb_pck_pack>1) { + ts_pack_buffer = gf_malloc(sizeof(char) * 188 * nb_pck_pack); + } + + /*****************/ + /* main loop */ + /*****************/ + last_print_time = gf_sys_clock(); + while (run) { + u32 status; + + /*check for some audio input from the network*/ + if (audio_input_ip) { + u32 read; + switch (audio_input_type) { + case GF_MP42TS_UDP: + case GF_MP42TS_RTP: + /*e =*/ + gf_sk_receive(audio_input_udp_sk, audio_input_buffer, audio_input_buffer_length, 0, &read); + if (read) { + SampleCallBack((void*)&sources[nb_sources-1], AUDIO_DATA_ESID, audio_input_buffer, read, gf_m2ts_get_sys_clock(muxer)); + } + break; +#ifndef GPAC_DISABLE_PLAYER + case GF_MP42TS_HTTP: + /*nothing to do: AAC_OnLiveData is called automatically*/ + /*check we're still alive*/ + if (gf_dm_is_thread_dead(aac_reader->dnload)) { + GF_ESD *esd; + aac_download_file(aac_reader, audio_input_ip); + esd = AAC_GetESD(aac_reader); + if (!esd) + break; + assert(esd->slConfig->timestampResolution); /*if we don't have this value we won't be able to adjust the timestamps within the MPEG2-TS*/ + if (esd->slConfig->timestampResolution) + audio_discontinuity_offset = gf_m2ts_get_sys_clock(muxer) * (u64)esd->slConfig->timestampResolution / 1000; + gf_odf_desc_del((GF_Descriptor *)esd); + } + break; +#endif + default: + assert(0); + } + } + + /*flush all packets*/ + nb_pck_in_pack=0; + while ((ts_pck = gf_m2ts_mux_process(muxer, &status, &usec_till_next)) != NULL) { + + if (ts_pack_buffer ) { + memcpy(ts_pack_buffer + 188 * nb_pck_in_pack, ts_pck, 188); + nb_pck_in_pack++; + + if (nb_pck_in_pack < nb_pck_pack) + continue; + + ts_pck = (const char *) ts_pack_buffer; + } else { + nb_pck_in_pack = 1; + } + +call_flush: + if (ts_output_file != NULL) { + gf_fwrite(ts_pck, 1, 188 * nb_pck_in_pack, ts_output_file); + if (segment_duration && (muxer->time.sec > prev_seg_time.sec + segment_duration)) { + prev_seg_time = muxer->time; + gf_fclose(ts_output_file); + segment_index++; + if (segment_dir) { + if (strchr("\\/", segment_name[strlen(segment_name)-1])) { + sprintf(segment_name, "%s%s_%d.ts", segment_dir, segment_prefix, segment_index); + } else { + sprintf(segment_name, "%s/%s_%d.ts", segment_dir, segment_prefix, segment_index); + } + } else { + sprintf(segment_name, "%s_%d.ts", segment_prefix, segment_index); + } + ts_output_file = gf_fopen(segment_name, "wb"); + if (!ts_output_file) { + fprintf(stderr, "Error opening %s\n", segment_name); + goto exit; + } + /* delete the oldest segment */ + if (segment_number && ((s32) (segment_index - segment_number - 1) >= 0)) { + char old_segment_name[GF_MAX_PATH]; + if (segment_dir) { + if (strchr("\\/", segment_name[strlen(segment_name)-1])) { + sprintf(old_segment_name, "%s%s_%d.ts", segment_dir, segment_prefix, segment_index - segment_number - 1); + } else { + sprintf(old_segment_name, "%s/%s_%d.ts", segment_dir, segment_prefix, segment_index - segment_number - 1); + } + } else { + sprintf(old_segment_name, "%s_%d.ts", segment_prefix, segment_index - segment_number - 1); + } + gf_delete_file(old_segment_name); + } + write_manifest(segment_manifest, segment_dir, segment_duration, segment_prefix, segment_http_prefix, +// (segment_index >= segment_number/2 ? segment_index - segment_number/2 : 0), segment_index >1 ? segment_index-1 : 0, 0); + ( (segment_index > segment_number ) ? segment_index - segment_number : 0), segment_index >1 ? segment_index-1 : 0, 0); + } + } + + if (ts_output_udp_sk != NULL) { + e = gf_sk_send(ts_output_udp_sk, (char*)ts_pck, 188 * nb_pck_in_pack); + if (e) { + fprintf(stderr, "Error %s sending UDP packet\n", gf_error_to_string(e)); + } + } +#ifndef GPAC_DISABLE_STREAMING + if (ts_output_rtp != NULL) { + u32 ts; + hdr.SequenceNumber++; + /*muxer clock at 90k*/ + ts = muxer->time.sec*90000 + muxer->time.nanosec*9/100000; + /*FIXME - better discontinuity check*/ + hdr.Marker = (ts < hdr.TimeStamp) ? 1 : 0; + hdr.TimeStamp = ts; + e = gf_rtp_send_packet(ts_output_rtp, &hdr, (char*)ts_pck, 188 * nb_pck_in_pack, 0); + if (e) { + fprintf(stderr, "Error %s sending RTP packet\n", gf_error_to_string(e)); + } + } +#endif + + nb_pck_in_pack = 0; + + if (status>=GF_M2TS_STATE_PADDING) { + break; + } + } + if (nb_pck_in_pack) { + ts_pck = (const char *) ts_pack_buffer; + goto call_flush; + } + + /*push video*/ + { + u32 now=gf_sys_clock(); + if (now/MP42TS_VIDEO_FREQ != last_video_time/MP42TS_VIDEO_FREQ) { + /*should use carrousel behaviour instead of being pushed manually*/ + if (video_buffer) + SampleCallBack((void*)&sources[nb_sources-1], VIDEO_DATA_ESID, video_buffer, video_buffer_size, gf_m2ts_get_sys_clock(muxer)+1000/*try buffering due to VLC msg*/); + last_video_time = now; + } + } + + if (real_time) { + /*refresh every MP42TS_PRINT_TIME_MS ms*/ + u32 now=gf_sys_clock(); + if (now > last_print_time + MP42TS_PRINT_TIME_MS) { + last_print_time = now; + fprintf(stderr, "M2TS: time % 6d - TS time % 6d - avg bitrate % 8d\r", gf_m2ts_get_sys_clock(muxer), gf_m2ts_get_ts_clock(muxer), muxer->average_birate_kbps); + + if (gf_prompt_has_input()) { + char c = gf_prompt_get_char(); + if (c=='q') break; + } + } + if (status == GF_M2TS_STATE_IDLE) { +#if 0 + /*wait till next packet is ready to be sent*/ + if (usec_till_next>1000) { + //fprintf(stderr, "%d usec till next packet\n", usec_till_next); + gf_sleep(usec_till_next / 1000); + } +#else + //we don't have enough precision on usec counting and we end up eating one core on most machines, so let's just sleep + //one second whenever we are idle - it's maybe too much but the muxer will catchup afterwards + gf_sleep(1); +#endif + } + } + + + if (run_time) { + if (gf_m2ts_get_ts_clock(muxer) > run_time) { + fprintf(stderr, "Stopping multiplex at %d ms (requested runtime %d ms)\n", gf_m2ts_get_ts_clock(muxer), run_time); + break; + } + } + if (status==GF_M2TS_STATE_EOS) { + break; + } + } + + { + u64 bits = muxer->tot_pck_sent*8*188; + u32 dur_sec = gf_m2ts_get_ts_clock(muxer) / 1000; + if (!dur_sec) dur_sec = 1; + fprintf(stderr, "Done muxing - %d sec - average rate %d kbps "LLD" packets written\n", dur_sec, (u32) (bits/dur_sec/1000), muxer->tot_pck_sent); + fprintf(stderr, "\tPadding: "LLD" packets - "LLD" PES padded bytes (%g kbps)\n", muxer->tot_pad_sent, muxer->tot_pes_pad_bytes, (Double) (muxer->tot_pes_pad_bytes*8.0/dur_sec/1000) ); + } + +exit: + if (ts_pack_buffer) gf_free(ts_pack_buffer); + run = 0; + if (segment_duration) { + write_manifest(segment_manifest, segment_dir, segment_duration, segment_prefix, segment_http_prefix, segment_index - segment_number, segment_index, 1); + } + if (ts_output_file && !is_stdout) gf_fclose(ts_output_file); + if (ts_output_udp_sk) gf_sk_del(ts_output_udp_sk); +#ifndef GPAC_DISABLE_STREAMING + if (ts_output_rtp) gf_rtp_del(ts_output_rtp); +#endif + if (ts_out) gf_free(ts_out); + if (audio_input_udp_sk) gf_sk_del(audio_input_udp_sk); + if (audio_input_buffer) gf_free (audio_input_buffer); + if (video_buffer) gf_free(video_buffer); + if (udp_out) gf_free(udp_out); +#ifndef GPAC_DISABLE_STREAMING + if (rtp_out) gf_free(rtp_out); +#endif + if (muxer) gf_m2ts_mux_del(muxer); + + for (i=0; i +#include +#include +#include +#include +#include + + +typedef struct __m2ts_mux_program M2TS_Mux_Program; +typedef struct __m2ts_mux M2TS_Mux; + +enum { + LOG_NO_LOG = 0, + LOG_PES = 1, + LOG_SECTION = 2, + LOG_TS = 3 +}; + + +typedef struct __m2ts_section { + struct __m2ts_section *next; + u8 *data; + u32 length; +} M2TS_Mux_Section; + +typedef struct __m2ts_table { + struct __m2ts_table *next; + u8 table_id; + u8 version_number; + struct __m2ts_section *section; +} M2TS_Mux_Table; + +typedef struct +{ + u32 sec; + u32 nanosec; +} M2TS_Time; + + +typedef struct __m2ts_mux_pck +{ + struct __m2ts_mux_pck *next; + char *data; + u32 data_len; + u32 flags; + u64 cts, dts; +} M2TS_Packet; + + +typedef struct __m2ts_mux_stream { + struct __m2ts_mux_stream *next; + + u32 pid; + u8 continuity_counter; + struct __m2ts_mux_program *program; + + /*average stream bit-rate in bit/sec*/ + u32 bit_rate; + + /*multiplexer time - NOT THE PCR*/ + M2TS_Time time; + + + /* MPEG-4 SL Config */ + GF_SLConfig sl_config; + + /*table tools*/ + M2TS_Mux_Table *tables; + /*total table sizes for bitrate estimation (PMT/PAT/...)*/ + u32 total_table_size; + /* used for on-the-fly packetization of sections */ + M2TS_Mux_Table *current_table; + M2TS_Mux_Section *current_section; + u32 current_section_offset; + u32 refresh_rate_ms; + Bool table_needs_update; + + Bool (*process)(struct __m2ts_mux *muxer, struct __m2ts_mux_stream *stream); + + /*PES tools*/ + void *pes_packetizer; + u32 mpeg2_stream_type; + u32 mpeg2_stream_id; + + GF_ESIPacket pck; + u32 pck_offset; + Bool force_new; + + struct __elementary_stream_ifce *ifce; + Double ts_scale; + u64 initial_ts; + + /*packet fifo*/ + M2TS_Packet *pck_first, *pck_last; + /*packet reassembler (PES packets are most of the time full frames)*/ + M2TS_Packet *pck_reassembler; + GF_Mutex *mx; + /*avg bitrate compute*/ + u64 last_br_time; + u32 bytes_since_last_time; + + /*MPEG-4 over MPEG-2*/ + u8 table_id; + GF_SLHeader sl_header; + //GF_SLConfig sl_config; + + u32 last_aac_time; +} M2TS_Mux_Stream; + + +struct __m2ts_mux_program { + struct __m2ts_mux_program *next; + + struct __m2ts_mux *mux; + u16 number; + /*all streams but PMT*/ + M2TS_Mux_Stream *streams; + /*PMT*/ + M2TS_Mux_Stream *pmt; + /*pointer to PCR stream*/ + M2TS_Mux_Stream *pcr; + + /*TS time at pcr init*/ + M2TS_Time ts_time_at_pcr_init; + u64 pcr_init_time, num_pck_at_pcr_init; + u64 last_pcr; + u32 last_sys_clock; + + GF_Descriptor *iod; +}; + +struct __m2ts_mux { + M2TS_Mux_Program *programs; + M2TS_Mux_Stream *pat; + + u16 ts_id; + + Bool needs_reconfig; + + /* used to indicate that the input data is pushed to the muxer (i.e. not read from a file) + or that the output data is sent on sockets (not written to a file) */ + Bool real_time; + + /* indicates if the multiplexer shall target a fix bit rate (monitoring timing and produce padding packets) + or if the output stream will contain only input data*/ + Bool fixed_rate; + + /*output bit-rate in bit/sec*/ + u32 bit_rate; + + char dst_pck[188], null_pck[188]; + + /*multiplexer time, incremented each time a packet is sent + used to monitor the sending of muxer related data (PAT, ...) */ + M2TS_Time time; + + /* Time of the muxer when the first call to process is made (first packet sent?) */ + M2TS_Time init_ts_time; + + /* System time when the muxer is started */ + u32 init_sys_time; + + Bool eos_found; + u32 pck_sent_over_br_window, last_br_time, avg_br; + u64 tot_pck_sent, tot_pad_sent; + + Bool mpeg4_signaling; +}; + + +enum +{ + GF_M2TS_STATE_IDLE, + GF_M2TS_STATE_DATA, + GF_M2TS_STATE_PADDING, + GF_M2TS_STATE_EOS, +}; + diff --git a/applications/mp4box/Makefile b/applications/mp4box/Makefile new file mode 100644 index 0000000..fde035a --- /dev/null +++ b/applications/mp4box/Makefile @@ -0,0 +1,88 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/applications/mp4box + +CFLAGS= $(OPTFLAGS) -DGPAC_HAVE_CONFIG_H -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS=main.o filedump.o fileimport.o +ifeq ($(DISABLE_STREAMING),no) +OBJS+=live.o +endif + +LINKFLAGS=-L../../bin/gcc -L../../extra_lib/lib/gcc + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=MP4Box$(EXE) + +ifeq ($(MP4BOX_STATIC),yes) +LINKFLAGS+=-lgpac_static $(EXTRALIBS) +ifneq ($(CONFIG_ZLIB),no) +LINKFLAGS+=-lz +endif + +else +LINKFLAGS+=-lgpac +endif + +else + +EXT= +PROG=MP4Box + +ifeq ($(MP4BOX_STATIC),yes) + +LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS) + +ifneq ($(CONFIG_ZLIB),no) +LINKFLAGS+=-lz +endif + +# spidermonkey support +ifeq ($(CONFIG_JS),no) +else +SCENEGRAPH_CFLAGS+=$(JS_FLAGS) +ifeq ($(CONFIG_JS),local) +NEED_LOCAL_LIB="yes" +endif +LINKFLAGS+=$(JS_LIBS) +endif + +else +LINKFLAGS+=-lgpac +endif + +endif + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/mp4box/filedump.c b/applications/mp4box/filedump.c new file mode 100644 index 0000000..b2ca565 --- /dev/null +++ b/applications/mp4box/filedump.c @@ -0,0 +1,2956 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2000-2012 + * All rights reserved + * + * This file is part of GPAC / mp4box application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +#if defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE) + +#error "Cannot compile MP4Box if GPAC is not built with ISO File Format support" + +#else + +#ifndef GPAC_DISABLE_X3D +#include +#endif +#ifndef GPAC_DISABLE_BIFS +#include +#endif +#ifndef GPAC_DISABLE_VRML +#include +#endif +#include +#include +#include +/*for asctime and gmtime*/ +#include +/*ISO 639 languages*/ +#include +#include + +#ifndef GPAC_DISABLE_SMGR +#include +#endif +#include + +extern u32 swf_flags; +extern Float swf_flatten_angle; +extern GF_FileType get_file_type_by_ext(char *inName); + +void scene_coding_log(void *cbk, u32 log_level, u32 log_tool, const char *fmt, va_list vlist); + +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) +GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample); +#endif + +void PrintLanguages() +{ + u32 i=0, count = gf_lang_get_count(); + fprintf(stderr, "Supported ISO 639 languages and codes:\n\n"); + for (i=0; i=0) return gf_lang_get_name(idx); + return lcode; +} + +GF_Err dump_cover_art(GF_ISOFile *file, char *inName) +{ + const char *tag; + char szName[1024]; + FILE *t; + u32 tag_len; + GF_Err e = gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_COVER_ART, &tag, &tag_len); + if (e!=GF_OK) { + if (e==GF_URL_ERROR) { + fprintf(stderr, "No cover art found\n"); + return GF_OK; + } + return e; + } + + sprintf(szName, "%s.%s", inName, (tag_len>>31) ? "png" : "jpg"); + t = gf_fopen(szName, "wb"); + gf_fwrite(tag, tag_len & 0x7FFFFFFF, 1, t); + + gf_fclose(t); + return GF_OK; +} + +#ifndef GPAC_DISABLE_ISOM_WRITE + +GF_Err set_cover_art(GF_ISOFile *file, char *inName) +{ + GF_Err e; + char *tag, *ext; + FILE *t; + u32 tag_len; + t = gf_fopen(inName, "rb"); + gf_fseek(t, 0, SEEK_END); + tag_len = (u32) gf_ftell(t); + gf_fseek(t, 0, SEEK_SET); + tag = gf_malloc(sizeof(char) * tag_len); + tag_len = (u32) fread(tag, sizeof(char), tag_len, t); + gf_fclose(t); + + ext = strrchr(inName, '.'); + if (!stricmp(ext, ".png")) tag_len |= 0x80000000; + e = gf_isom_apple_set_tag(file, GF_ISOM_ITUNE_COVER_ART, tag, tag_len); + gf_free(tag); + return e; +} + +#endif + +#ifndef GPAC_DISABLE_SCENE_DUMP + +GF_Err dump_file_text(char *file, char *inName, GF_SceneDumpFormat dump_mode, Bool do_log) +{ + GF_Err e; + GF_SceneManager *ctx; + GF_SceneGraph *sg; + GF_SceneLoader load; + GF_FileType ftype; + gf_log_cbk prev_logs = NULL; + FILE *logs = NULL; + e = GF_OK; + + sg = gf_sg_new(); + ctx = gf_sm_new(sg); + memset(&load, 0, sizeof(GF_SceneLoader)); + load.fileName = file; + load.ctx = ctx; + load.swf_import_flags = swf_flags; + if (dump_mode == GF_SM_DUMP_SVG) { + load.swf_import_flags |= GF_SM_SWF_USE_SVG; + load.svgOutFile = inName; + } + load.swf_flatten_limit = swf_flatten_angle; + + ftype = get_file_type_by_ext(file); + if (ftype == GF_FILE_TYPE_ISO_MEDIA) { + load.isom = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL); + if (!load.isom) { + e = gf_isom_last_error(NULL); + fprintf(stderr, "Error opening file: %s\n", gf_error_to_string(e)); + gf_sm_del(ctx); + gf_sg_del(sg); + return e; + } + } else if (ftype==GF_FILE_TYPE_LSR_SAF) { + load.isom = gf_isom_open("saf_conv", GF_ISOM_WRITE_EDIT, NULL); +#ifndef GPAC_DISABLE_MEDIA_IMPORT + if (load.isom) + e = import_file(load.isom, file, 0, 0, 0); + else +#else + fprintf(stderr, "Warning: GPAC was compiled without Media Import support\n"); +#endif + e = gf_isom_last_error(NULL); + + if (e) { + fprintf(stderr, "Error importing file: %s\n", gf_error_to_string(e)); + gf_sm_del(ctx); + gf_sg_del(sg); + if (load.isom) gf_isom_delete(load.isom); + return e; + } + } + + if (do_log) { + char szLog[GF_MAX_PATH]; + sprintf(szLog, "%s_dec.logs", inName); + logs = gf_fopen(szLog, "wt"); + + gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_DEBUG); + prev_logs = gf_log_set_callback(logs, scene_coding_log); + } + e = gf_sm_load_init(&load); + if (!e) e = gf_sm_load_run(&load); + gf_sm_load_done(&load); + if (logs) { + gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_ERROR); + gf_log_set_callback(NULL, prev_logs); + gf_fclose(logs); + } + if (!e && dump_mode != GF_SM_DUMP_SVG) { + u32 count = gf_list_count(ctx->streams); + if (count) + fprintf(stderr, "Scene loaded - dumping %d systems streams\n", count); + else + fprintf(stderr, "Scene loaded - dumping root scene\n"); + + e = gf_sm_dump(ctx, inName, dump_mode); + } + + gf_sm_del(ctx); + gf_sg_del(sg); + if (e) fprintf(stderr, "Error loading scene: %s\n", gf_error_to_string(e)); + if (load.isom) gf_isom_delete(load.isom); + return e; +} +#endif + +#ifndef GPAC_DISABLE_SCENE_STATS + +static void dump_stats(FILE *dump, GF_SceneStatistics *stats) +{ + u32 i; + s32 created, count, draw_created, draw_count, deleted, draw_deleted; + created = count = draw_created = draw_count = deleted = draw_deleted = 0; + + fprintf(dump, "\n"); + fprintf(dump, "\n", gf_list_count(stats->node_stats)); + for (i=0; inode_stats); i++) { + GF_NodeStats *ptr = gf_list_get(stats->node_stats, i); + fprintf(dump, "\n", ptr->name); + + switch (ptr->tag) { +#ifndef GPAC_DISABLE_VRML + case TAG_MPEG4_Bitmap: + case TAG_MPEG4_Background2D: + case TAG_MPEG4_Background: + case TAG_MPEG4_Box: + case TAG_MPEG4_Circle: + case TAG_MPEG4_CompositeTexture2D: + case TAG_MPEG4_CompositeTexture3D: + case TAG_MPEG4_Cylinder: + case TAG_MPEG4_Cone: + case TAG_MPEG4_Curve2D: + case TAG_MPEG4_Extrusion: + case TAG_MPEG4_ElevationGrid: + case TAG_MPEG4_IndexedFaceSet2D: + case TAG_MPEG4_IndexedFaceSet: + case TAG_MPEG4_IndexedLineSet2D: + case TAG_MPEG4_IndexedLineSet: + case TAG_MPEG4_PointSet2D: + case TAG_MPEG4_PointSet: + case TAG_MPEG4_Rectangle: + case TAG_MPEG4_Sphere: + case TAG_MPEG4_Text: + case TAG_MPEG4_Ellipse: + case TAG_MPEG4_XCurve2D: + draw_count += ptr->nb_created + ptr->nb_used - ptr->nb_del; + draw_deleted += ptr->nb_del; + draw_created += ptr->nb_created; + break; +#endif /*GPAC_DISABLE_VRML*/ + } + fprintf(dump, "\n", ptr->nb_created, ptr->nb_used, ptr->nb_del); + count += ptr->nb_created + ptr->nb_used; + deleted += ptr->nb_del; + created += ptr->nb_created; + fprintf(dump, "\n"); + } + if (i) { + fprintf(dump, "\n", count, created, deleted, stats->nb_svg_attributes); + fprintf(dump, "\n", draw_count, draw_created, draw_deleted); + } + fprintf(dump, "\n"); + + created = count = deleted = 0; + if (gf_list_count(stats->proto_stats)) { + fprintf(dump, "\n", gf_list_count(stats->proto_stats)); + for (i=0; iproto_stats); i++) { + GF_NodeStats *ptr = gf_list_get(stats->proto_stats, i); + fprintf(dump, "\n", ptr->name); + fprintf(dump, "\n", ptr->nb_created, ptr->nb_used, ptr->nb_del); + count += ptr->nb_created + ptr->nb_used; + deleted += ptr->nb_del; + created += ptr->nb_created; + fprintf(dump, "\n"); + } + if (i) fprintf(dump, "\n", count, created, deleted); + fprintf(dump, "\n"); + } + fprintf(dump, "\n", FIX2FLT( stats->min_fixed) , FIX2FLT( stats->max_fixed )); + fprintf(dump, "\n", stats->scale_int_res_2d, stats->scale_frac_res_2d, stats->int_res_2d, stats->frac_res_2d); + fprintf(dump, "\n"); + fprintf(dump, "\n"); + fprintf(dump, "\n", stats->count_2d, stats->rem_2d); + if (stats->count_2d) { + fprintf(dump, "\n", FIX2FLT( stats->min_2d.x) , FIX2FLT( stats->min_2d.y ), FIX2FLT( stats->max_2d.x ), FIX2FLT( stats->max_2d.y ) ); + } + fprintf(dump, "\n"); + + fprintf(dump, "\n"); + fprintf(dump, "", stats->count_3d, stats->rem_3d); + if (stats->count_3d) { + fprintf(dump, "\n", FIX2FLT( stats->min_3d.x ), FIX2FLT( stats->min_3d.y ), FIX2FLT( stats->min_3d.z ), FIX2FLT( stats->max_3d.x ), FIX2FLT( stats->max_3d.y ), FIX2FLT( stats->max_3d.z ) ); + } + fprintf(dump, "\n"); + + fprintf(dump, "\n"); + fprintf(dump, "", stats->count_color, stats->rem_color); + fprintf(dump, "\n"); + + fprintf(dump, "\n"); + fprintf(dump, "", stats->count_float, stats->rem_float); + fprintf(dump, "\n"); + + fprintf(dump, "\n"); + fprintf(dump, "", stats->count_2f); + fprintf(dump, "\n"); + fprintf(dump, "\n"); + fprintf(dump, "", stats->count_3f); + fprintf(dump, "\n"); +} + + +static void ReorderAU(GF_List *sample_list, GF_AUContext *au) +{ + u32 i; + for (i=0; itiming_sec > au->timing_sec) + /*set bifs first*/ + || ((ptr->timing_sec == au->timing_sec) && (ptr->owner->streamType < au->owner->streamType)) + ) { + gf_list_insert(sample_list, au, i); + return; + } + } + gf_list_add(sample_list, au); +} + +void dump_scene_stats(char *file, char *inName, u32 stat_level) +{ + GF_Err e; + FILE *dump; + Bool close; + u32 i, j, count; + char szBuf[1024]; + GF_SceneManager *ctx; + GF_SceneLoader load; + GF_StatManager *sm; + GF_List *sample_list; + GF_SceneGraph *scene_graph; + + dump = NULL; + sm = NULL; + sample_list = NULL; + + close = 0; + + scene_graph = gf_sg_new(); + ctx = gf_sm_new(scene_graph); + memset(&load, 0, sizeof(GF_SceneLoader)); + load.fileName = file; + load.ctx = ctx; + + if (get_file_type_by_ext(file) == 1) { + load.isom = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL); + if (!load.isom) { + fprintf(stderr, "Cannot open file: %s\n", gf_error_to_string(gf_isom_last_error(NULL))); + gf_sm_del(ctx); + gf_sg_del(scene_graph); + return; + } + } + + e = gf_sm_load_init(&load); + if (!e) e = gf_sm_load_run(&load); + gf_sm_load_done(&load); + if (e) goto exit; + + if (inName) { + strcpy(szBuf, inName); + strcat(szBuf, "_stat.xml"); + dump = gf_fopen(szBuf, "wt"); + close = 1; + } else { + dump = stderr; + close = 0; + } + + fprintf(stderr, "Analysing Scene\n"); + + fprintf(dump, "\n"); + fprintf(dump, "\n"); + fprintf(dump, "\n", file, (stat_level==1) ? "full scene" : ((stat_level==2) ? "AccessUnit based" : "SceneGraph after each AU")); + + sm = gf_sm_stats_new(); + + /*stat level 1: complete scene stat*/ + if (stat_level == 1) { + e = gf_sm_stats_for_scene(sm, ctx); + if (!e) dump_stats(dump, gf_sm_stats_get(sm) ); + goto exit; + } + /*re_order all BIFS-AUs*/ + sample_list = gf_list_new(); + /*configure all systems streams we're dumping*/ + for (i=0; istreams); i++) { + GF_StreamContext *sc = gf_list_get(ctx->streams, i); + if (sc->streamType != GF_STREAM_SCENE) continue; + for (j=0; jAUs); j++) { + GF_AUContext *au = gf_list_get(sc->AUs, j); + ReorderAU(sample_list, au); + } + } + + count = gf_list_count(sample_list); + for (i=0; icommands); j++) { + GF_Command *com = gf_list_get(au->commands, j); + /*stat level 2 - get command stats*/ + if (stat_level==2) { + e = gf_sm_stats_for_command(sm, com); + if (e) goto exit; + } + /*stat level 3 - apply command*/ + if (stat_level==3) gf_sg_command_apply(scene_graph, com, 0); + } + /*stat level 3: get graph stat*/ + if (stat_level==3) { + e = gf_sm_stats_for_graph(sm, scene_graph); + if (e) goto exit; + } + if (stat_level==2) { + fprintf(dump, "\n", au->owner->ESID, LLD_CAST au->timing); + } else { + fprintf(dump, "\n", au->owner->ESID, LLD_CAST au->timing); + } + /*dump stats*/ + dump_stats(dump, gf_sm_stats_get(sm) ); + /*reset stats*/ + gf_sm_stats_reset(sm); + if (stat_level==2) { + fprintf(dump, "\n"); + } else { + fprintf(dump, "\n"); + } + + gf_set_progress("Analysing AU", i+1, count); + } + + +exit: + if (sample_list) gf_list_del(sample_list); + if (sm) gf_sm_stats_del(sm); + gf_sm_del(ctx); + gf_sg_del(scene_graph); + if (e) { + fprintf(stderr, "%s\n", gf_error_to_string(e)); + } else { + fprintf(dump, "\n"); + } + if (dump && close) gf_fclose(dump); + fprintf(stderr, "done\n"); +} +#endif /*GPAC_DISABLE_SCENE_STATS*/ + + + +#ifndef GPAC_DISABLE_VRML + +static void PrintFixed(Fixed val, Bool add_space) +{ + if (add_space) fprintf(stderr, " "); + if (val==FIX_MIN) fprintf(stderr, "-I"); + else if (val==FIX_MAX) fprintf(stderr, "+I"); + else fprintf(stderr, "%g", FIX2FLT(val)); +} + +static void PrintNodeSFField(u32 type, void *far_ptr) +{ + if (!far_ptr) return; + switch (type) { + case GF_SG_VRML_SFBOOL: + fprintf(stderr, "%s", (*(SFBool *)far_ptr) ? "TRUE" : "FALSE"); + break; + case GF_SG_VRML_SFINT32: + fprintf(stderr, "%d", (*(SFInt32 *)far_ptr)); + break; + case GF_SG_VRML_SFFLOAT: + PrintFixed((*(SFFloat *)far_ptr), 0); + break; + case GF_SG_VRML_SFTIME: + fprintf(stderr, "%g", (*(SFTime *)far_ptr)); + break; + case GF_SG_VRML_SFVEC2F: + PrintFixed(((SFVec2f *)far_ptr)->x, 0); + PrintFixed(((SFVec2f *)far_ptr)->y, 1); + break; + case GF_SG_VRML_SFVEC3F: + PrintFixed(((SFVec3f *)far_ptr)->x, 0); + PrintFixed(((SFVec3f *)far_ptr)->y, 1); + PrintFixed(((SFVec3f *)far_ptr)->z, 1); + break; + case GF_SG_VRML_SFROTATION: + PrintFixed(((SFRotation *)far_ptr)->x, 0); + PrintFixed(((SFRotation *)far_ptr)->y, 1); + PrintFixed(((SFRotation *)far_ptr)->z, 1); + PrintFixed(((SFRotation *)far_ptr)->q, 1); + break; + case GF_SG_VRML_SFCOLOR: + PrintFixed(((SFColor *)far_ptr)->red, 0); + PrintFixed(((SFColor *)far_ptr)->green, 1); + PrintFixed(((SFColor *)far_ptr)->blue, 1); + break; + case GF_SG_VRML_SFSTRING: + if (((SFString*)far_ptr)->buffer) + fprintf(stderr, "\"%s\"", ((SFString*)far_ptr)->buffer); + else + fprintf(stderr, "NULL"); + break; + } +} +#endif + +void PrintNode(const char *name, u32 graph_type) +{ +#ifdef GPAC_DISABLE_VRML + fprintf(stderr, "VRML/MPEG-4/X3D scene graph is disabled in this build of GPAC\n"); + return; +#else + const char *nname, *std_name; + char szField[1024]; + GF_Node *node; + GF_SceneGraph *sg; + u32 tag, nbF, i; + GF_FieldInfo f; +#ifndef GPAC_DISABLE_BIFS + u8 qt, at; + Fixed bmin, bmax; + u32 nbBits; +#endif /*GPAC_DISABLE_BIFS*/ + Bool is_nodefield = 0; + + char *sep = strchr(name, '.'); + if (sep) { + strcpy(szField, sep+1); + sep[0] = 0; + is_nodefield = 1; + } + + tag = 0; + if (graph_type==2) { + fprintf(stderr, "SVG node printing is not supported\n"); + return; + } else if (graph_type==1) { +#ifndef GPAC_DISABLE_X3D + tag = gf_node_x3d_type_by_class_name(name); + std_name = "X3D"; +#else + fprintf(stderr, "X3D node printing is not supported (X3D support disabled)\n"); + return; +#endif + } else { + tag = gf_node_mpeg4_type_by_class_name(name); + std_name = "MPEG4"; + } + if (!tag) { + fprintf(stderr, "Unknown %s node %s\n", std_name, name); + return; + } + + sg = gf_sg_new(); + node = gf_node_new(sg, tag); + gf_node_register(node, NULL); + nname = gf_node_get_class_name(node); + if (!node) { + fprintf(stderr, "Node %s not supported in current built\n", nname); + return; + } + nbF = gf_node_get_field_count(node); + + if (is_nodefield) { + u32 tfirst, tlast; + if (gf_node_get_field_by_name(node, szField, &f) != GF_OK) { + fprintf(stderr, "Field %s is not a member of node %s\n", szField, name); + return; + } + fprintf(stderr, "Allowed nodes in %s.%s:\n", name, szField); + if (graph_type==1) { + tfirst = GF_NODE_RANGE_FIRST_X3D; + tlast = GF_NODE_RANGE_LAST_X3D; + } else { + tfirst = GF_NODE_RANGE_FIRST_MPEG4; + tlast = GF_NODE_RANGE_LAST_MPEG4; + } + for (i=tfirst; icount; i++) { + if (i) fprintf(stderr, " "); + gf_sg_vrml_mf_get_item(f.far_ptr, f.fieldType, &ptr, i); + PrintNodeSFField(sftype, ptr); + } + fprintf(stderr, "]"); + } +#ifndef GPAC_DISABLE_BIFS + if (gf_bifs_get_aq_info(node, i, &qt, &at, &bmin, &bmax, &nbBits)) { + if (qt) { + fprintf(stderr, " #QP=%d", qt); + if (qt==13) fprintf(stderr, " NbBits=%d", nbBits); + if (bmin && bmax) { + fprintf(stderr, " Bounds=["); + PrintFixed(bmin, 0); + fprintf(stderr, ","); + PrintFixed(bmax, 0); + fprintf(stderr, "]"); + } + } + } +#endif /*GPAC_DISABLE_BIFS*/ + fprintf(stderr, "\n"); + } + fprintf(stderr, "}\n\n"); + + gf_node_unregister(node, NULL); + gf_sg_del(sg); +#endif /*GPAC_DISABLE_VRML*/ +} + +void PrintBuiltInNodes(u32 graph_type) +{ +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_SVG) + GF_Node *node; + GF_SceneGraph *sg; + u32 i, nb_in, nb_not_in, start_tag, end_tag; + + if (graph_type==1) { +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) + start_tag = GF_NODE_RANGE_FIRST_X3D; + end_tag = TAG_LastImplementedX3D; +#else + fprintf(stderr, "X3D scene graph disabled in this build of GPAC\n"); + return; +#endif + } else if (graph_type==2) { +#ifdef GPAC_DISABLE_SVG + fprintf(stderr, "SVG scene graph disabled in this build of GPAC\n"); + return; +#else + start_tag = GF_NODE_RANGE_FIRST_SVG; + end_tag = GF_NODE_RANGE_LAST_SVG; +#endif + } else { +#ifdef GPAC_DISABLE_VRML + fprintf(stderr, "VRML/MPEG-4 scene graph disabled in this build of GPAC\n"); + return; +#else + start_tag = GF_NODE_RANGE_FIRST_MPEG4; + end_tag = TAG_LastImplementedMPEG4; +#endif + } + nb_in = nb_not_in = 0; + sg = gf_sg_new(); + + if (graph_type==1) { + fprintf(stderr, "Available X3D nodes in this build (dumping):\n"); + } else if (graph_type==2) { + fprintf(stderr, "Available SVG nodes in this build (dumping and LASeR coding):\n"); + } else { + fprintf(stderr, "Available MPEG-4 nodes in this build (encoding/decoding/dumping):\n"); + } + for (i=start_tag; i\n"); + fprintf(dump, "\n"); + fprintf(dump, "\n"); + + for (i=0; i\n", gf_isom_get_track_id(file, i+1)); + gf_isom_sdp_track_get(file, i+1, &sdp, &size); + fprintf(dump, "%s", sdp); + + for (j=0; j\n"); + } + fprintf(dump, "\n"); + if (inName) gf_fclose(dump); +} +#endif + +void dump_file_timestamps(GF_ISOFile *file, char *inName) +{ + u32 i, j, k, count; + Bool has_error; + FILE *dump; + char szBuf[1024]; + + if (inName) { + strcpy(szBuf, inName); + strcat(szBuf, "_ts.txt"); + dump = gf_fopen(szBuf, "wt"); + } else { + dump = stderr; + } + + has_error = 0; + for (i=0; iDTS; + cts = dts + (s32) samp->CTS_Offset; + fprintf(dump, "Sample %d\tDTS "LLD"\tCTS "LLD"\t%d\t%d\t"LLD"\t%d\t%d\t%d\t%d\t%d\t%d\t%d", j+1, LLD_CAST dts, LLD_CAST cts, samp->dataLength, samp->IsRAP, offset, isLeading, dependsOn, dependedOn, redundant, is_rap, has_roll, roll_distance); + if (ctsDTS; + acts = adts + (s32) samp->CTS_Offset; + + if (adts==dts) { + fprintf(dump, " #SAME DTS USED!!!"); + has_error = 1; + } + if (acts==cts) { + fprintf(dump, " #SAME CTS USED!!! "); + has_error = 1; + } + + gf_isom_sample_del(&samp); + } + } + + fprintf(dump, "\n"); + gf_set_progress("Analysing Track Timing", j+1, count); + } + fprintf(dump, "\n\n"); + gf_set_progress("Analysing Track Timing", count, count); + } + if (inName) gf_fclose(dump); + if (has_error) fprintf(stderr, "\tFile has CTTS table errors\n"); +} + + +#ifndef GPAC_DISABLE_AV_PARSERS + +static u32 read_nal_size_hdr(char *ptr, u32 nalh_size) +{ + u32 nal_size=0; + u32 v = nalh_size; + while (v) { + nal_size |= (u8) *ptr; + ptr++; + v-=1; + if (v) nal_size <<= 8; + } + return nal_size; +} + +static void dump_sei(FILE *dump, u8 *ptr, u32 ptr_size, Bool is_hevc) +{ + u32 sei_idx=0; + u32 i=2; + fprintf(dump, " SEI=\""); + while (i+1 < ptr_size) { + u32 sei_type = 0; + u32 sei_size = 0; + while (ptr[i] == 0xFF) { + sei_type+= 255; + i++; + } + sei_type += ptr[i]; + i++; + while (ptr[i] == 0xFF) { + sei_size += 255; + i++; + } + sei_size += ptr[i]; + i++; + i+=sei_size; + + if (sei_idx) fprintf(dump, ","); + fprintf(dump, "(type=%u, size=%u)", sei_type, sei_size); + sei_idx++; + if (ptr[i]== 0x80) { + i=ptr_size; + break; + } + } + if (i!=ptr_size) fprintf(dump, "(garbage at end)"); + fprintf(dump, "\""); +} + +static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_hevc, AVCState *avc, u32 nalh_size) +{ + s32 res; + u8 type; + u8 dependency_id, quality_id, temporal_id; + u8 track_ref_index; + s8 sample_offset; + u32 data_offset, idx, data_size; + GF_BitStream *bs; + + if (is_hevc) { +#ifndef GPAC_DISABLE_HEVC + type = (ptr[0] & 0x7E) >> 1; + fprintf(dump, "code=\"%d\" type=\"", type); + switch (type) { + case GF_HEVC_NALU_SLICE_TRAIL_N: + fputs("TRAIL_N slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_TRAIL_R: + fputs("TRAIL_R slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_TSA_N: + fputs("TSA_N slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_TSA_R: + fputs("TSA_R slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_STSA_N: + fputs("STSA_N slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_STSA_R: + fputs("STSA_R slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_RADL_N: + fputs("RADL_N slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_RADL_R: + fputs("RADL_R slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_RASL_N: + fputs("RASL_N slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_RASL_R: + fputs("RASL_R slice segment", dump); + break; + case GF_HEVC_NALU_SLICE_BLA_W_LP: + fputs("Broken link access slice (W LP)", dump); + break; + case GF_HEVC_NALU_SLICE_BLA_W_DLP: + fputs("Broken link access slice (W DLP)", dump); + break; + case GF_HEVC_NALU_SLICE_BLA_N_LP: + fputs("Broken link access slice (N LP)", dump); + break; + case GF_HEVC_NALU_SLICE_IDR_W_DLP: + fputs("IDR slice (W DLP)", dump); + break; + case GF_HEVC_NALU_SLICE_IDR_N_LP: + fputs("IDR slice (N LP)", dump); + break; + case GF_HEVC_NALU_SLICE_CRA: + fputs("CRA slice", dump); + break; + + case GF_HEVC_NALU_VID_PARAM: + fputs("Video Parameter Set", dump); + break; + case GF_HEVC_NALU_SEQ_PARAM: + fputs("Sequence Parameter Set", dump); + break; + case GF_HEVC_NALU_PIC_PARAM: + fputs("Picture Parameter Set", dump); + break; + case GF_HEVC_NALU_ACCESS_UNIT: + fputs("AU Delimiter", dump); + break; + case GF_HEVC_NALU_END_OF_SEQ: + fputs("End of Sequence", dump); + break; + case GF_HEVC_NALU_END_OF_STREAM: + fputs("End of Stream", dump); + break; + case GF_HEVC_NALU_FILLER_DATA: + fputs("Filler Data", dump); + break; + case GF_HEVC_NALU_SEI_PREFIX: + fputs("SEI Prefix", dump); + break; + case GF_HEVC_NALU_SEI_SUFFIX: + fputs("SEI Suffix", dump); + break; + case 48: + fputs("HEVCAggregator", dump); + break; + case 49: + fputs("HEVCExtractor", dump); + track_ref_index = (u8) ptr[2]; + sample_offset = (s8) ptr[3]; + data_offset = read_nal_size_hdr(&ptr[4], nalh_size); + data_size = read_nal_size_hdr(&ptr[4+nalh_size], nalh_size); + fprintf(dump, "\" track_ref_index=\"%d\" sample_offset=\"%d\" data_offset=\"%d\" data_size=\"%d", track_ref_index, sample_offset, data_offset, data_size); + break; + default: + fputs("UNKNOWN", dump); + break; + } + fputs("\"", dump); + + if ((type==GF_HEVC_NALU_SEI_PREFIX) || (type==GF_HEVC_NALU_SEI_SUFFIX)) { + dump_sei(dump, (u8 *) ptr, ptr_size, is_hevc); + } + + fprintf(dump, " layer_id=\"%d\" temporal_id=\"%d\"", ((ptr[0] & 0x1) << 5) | (ptr[1]>>3), (ptr[1] & 0x7) ); +#endif //GPAC_DISABLE_HEVC + return; + } + + bs = gf_bs_new(ptr, ptr_size, GF_BITSTREAM_READ); + type = gf_bs_read_u8(bs) & 0x1F; + fprintf(dump, "code=\"%d\" type=\"", type); + res = 0; + switch (type) { + case GF_AVC_NALU_NON_IDR_SLICE: + res = gf_media_avc_parse_nalu(bs, ptr[0], avc); + fputs("Non IDR slice", dump); + + if (res>=0) + fprintf(dump, "\" poc=\"%d", avc->s_info.poc); + break; + case GF_AVC_NALU_DP_A_SLICE: + fputs("DP Type A slice", dump); + break; + case GF_AVC_NALU_DP_B_SLICE: + fputs("DP Type B slice", dump); + break; + case GF_AVC_NALU_DP_C_SLICE: + fputs("DP Type C slice", dump); + break; + case GF_AVC_NALU_IDR_SLICE: + res = gf_media_avc_parse_nalu(bs, ptr[0], avc); + fputs("IDR slice", dump); + if (res>=0) + fprintf(dump, "\" poc=\"%d", avc->s_info.poc); + break; + case GF_AVC_NALU_SEI: + fputs("SEI Message", dump); + break; + case GF_AVC_NALU_SEQ_PARAM: + fputs("SequenceParameterSet", dump); + idx = gf_media_avc_read_sps(ptr, ptr_size, avc, 0, NULL); + assert (idx >= 0); + fprintf(dump, "\" sps_id=\"%d", idx); + break; + case GF_AVC_NALU_PIC_PARAM: + fputs("PictureParameterSet", dump); + idx = gf_media_avc_read_pps(ptr, ptr_size, avc); + assert (idx >= 0); + fprintf(dump, "\" pps_id=\"%d\" sps_id=\"%d", idx, avc->pps[idx].sps_id); + break; + case GF_AVC_NALU_ACCESS_UNIT: + fputs("AccessUnit delimiter", dump); + break; + case GF_AVC_NALU_END_OF_SEQ: + fputs("EndOfSequence", dump); + break; + case GF_AVC_NALU_END_OF_STREAM: + fputs("EndOfStream", dump); + break; + case GF_AVC_NALU_FILLER_DATA: + fputs("Filler data", dump); + break; + case GF_AVC_NALU_SEQ_PARAM_EXT: + fputs("SequenceParameterSetExtension", dump); + break; + case GF_AVC_NALU_SVC_PREFIX_NALU: + fputs("SVCPrefix", dump); + break; + case GF_AVC_NALU_SVC_SUBSEQ_PARAM: + fputs("SVCSubsequenceParameterSet", dump); + idx = gf_media_avc_read_sps(ptr, ptr_size, avc, 1, NULL); + assert (idx >= 0); + fprintf(dump, "\" sps_id=\"%d", idx - GF_SVC_SSPS_ID_SHIFT); + break; + case GF_AVC_NALU_SLICE_AUX: + fputs("Auxiliary Slice", dump); + break; + + case GF_AVC_NALU_SVC_SLICE: + gf_media_avc_parse_nalu(bs, ptr[0], avc); + fputs(is_svc ? "SVCSlice" : "CodedSliceExtension", dump); + dependency_id = (ptr[2] & 0x70) >> 4; + quality_id = (ptr[2] & 0x0F); + temporal_id = (ptr[3] & 0xE0) >> 5; + fprintf(dump, "\" dependency_id=\"%d\" quality_id=\"%d\" temporal_id=\"%d", dependency_id, quality_id, temporal_id); + fprintf(dump, "\" poc=\"%d", avc->s_info.poc); + break; + case 30: + fputs("SVCAggregator", dump); + break; + case 31: + fputs("SVCExtractor", dump); + track_ref_index = (u8) ptr[4]; + sample_offset = (s8) ptr[5]; + data_offset = read_nal_size_hdr(&ptr[6], nalh_size); + data_size = read_nal_size_hdr(&ptr[6+nalh_size], nalh_size); + fprintf(dump, "\" track_ref_index=\"%d\" sample_offset=\"%d\" data_offset=\"%d\" data_size=\"%d\"", track_ref_index, sample_offset, data_offset, data_size); + break; + + default: + fputs("UNKNOWN", dump); + break; + } + fputs("\"", dump); + + if (type==GF_AVC_NALU_SEI) { + dump_sei(dump, (u8 *) ptr, ptr_size, is_hevc); + } + + if (res<0) + fprintf(dump, " status=\"error decoding slice\""); + + if (bs) gf_bs_del(bs); +} +#endif + +void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) +{ + u32 i, count, track, nalh_size, timescale, cur_extract_mode; + FILE *dump; + s32 countRef; + Bool is_adobe_protection = GF_FALSE; +#ifndef GPAC_DISABLE_AV_PARSERS + Bool is_hevc = GF_FALSE; + AVCState avc; + GF_AVCConfig *avccfg, *svccfg; + GF_HEVCConfig *hevccfg, *shvccfg; + GF_AVCConfigSlot *slc; +#endif + + track = gf_isom_get_track_by_id(file, trackID); + nalh_size = 0; + +#ifndef GPAC_DISABLE_AV_PARSERS + memset(&avc, 0, sizeof(AVCState)); + avccfg = gf_isom_avc_config_get(file, track, 1); + svccfg = gf_isom_svc_config_get(file, track, 1); + hevccfg = gf_isom_hevc_config_get(file, track, 1); + shvccfg = gf_isom_shvc_config_get(file, track, 1); + if (!avccfg && !svccfg && !hevccfg && !shvccfg) { + fprintf(stderr, "Error: Track #%d is not NALU-based!\n", trackID); + return; + } +#endif + + if (inName) { + char szBuf[GF_MAX_PATH]; + strcpy(szBuf, inName); + sprintf(szBuf, "%s_%d_nalu.xml", inName, trackID); + dump = gf_fopen(szBuf, "wt"); + } else { + dump = stderr; + } + + count = gf_isom_get_sample_count(file, track); + + timescale = gf_isom_get_media_timescale(file, track); + + cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track); + + fprintf(dump, "\n", trackID, count, timescale); + +#ifndef GPAC_DISABLE_AV_PARSERS + //for tile tracks the hvcC is stored in the 'tbas' track + if (!hevccfg && gf_isom_get_reference_count(file, track, GF_4CC('t','b','a','s'))) { + u32 tk = 0; + gf_isom_get_reference(file, track, GF_4CC('t','b','a','s'), 1, &tk); + hevccfg = gf_isom_hevc_config_get(file, tk, 1); + } + fprintf(dump, " \n"); + +#define DUMP_ARRAY(arr, name)\ + if (arr) {\ + for (i=0; isize);\ + dump_nalu(dump, slc->data, slc->size, svccfg ? 1 : 0, is_hevc, &avc, nalh_size);\ + fprintf(dump, "/>\n");\ + }\ + }\ + + nalh_size = 0; + + if (avccfg) { + nalh_size = avccfg->nal_unit_size; + + DUMP_ARRAY(avccfg->sequenceParameterSets, "AVCSPSArray") + DUMP_ARRAY(avccfg->pictureParameterSets, "AVCPPSArray") + DUMP_ARRAY(avccfg->sequenceParameterSetExtensions, "AVCSPSExArray") + } + if (svccfg) { + if (!nalh_size) nalh_size = svccfg->nal_unit_size; + DUMP_ARRAY(svccfg->sequenceParameterSets, "SVCSPSArray") + DUMP_ARRAY(svccfg->pictureParameterSets, "SVCPPSArray") + } + if (hevccfg) { +#ifndef GPAC_DISABLE_HEVC + u32 idx; + nalh_size = hevccfg->nal_unit_size; + is_hevc = 1; + for (idx=0; idxparam_array); idx++) { + GF_HEVCParamArray *ar = gf_list_get(hevccfg->param_array, idx); + if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { + DUMP_ARRAY(ar->nalus, "HEVCSPSArray") + } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { + DUMP_ARRAY(ar->nalus, "HEVCPPSArray") + } else if (ar->type==GF_HEVC_NALU_VID_PARAM) { + DUMP_ARRAY(ar->nalus, "HEVCVPSArray") + } else { + DUMP_ARRAY(ar->nalus, "HEVCUnknownPSArray") + } + } +#endif + } + if (shvccfg) { +#ifndef GPAC_DISABLE_HEVC + u32 idx; + nalh_size = shvccfg->nal_unit_size; + is_hevc = 1; + for (idx=0; idxparam_array); idx++) { + GF_HEVCParamArray *ar = gf_list_get(shvccfg->param_array, idx); + if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { + DUMP_ARRAY(ar->nalus, "HEVCSPSArray") + } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { + DUMP_ARRAY(ar->nalus, "HEVCPPSArray") + } else if (ar->type==GF_HEVC_NALU_VID_PARAM) { + DUMP_ARRAY(ar->nalus, "HEVCVPSArray") + } else { + DUMP_ARRAY(ar->nalus, "HEVCUnknownPSArray") + } + } +#endif + } + +#endif + fprintf(dump, " \n"); + + /*fixme: for dumping encrypted track: we don't have neither avccfg nor svccfg*/ + if (!nalh_size) nalh_size = 4; + + /*for testing dependency*/ + countRef = gf_isom_get_reference_count(file, track, GF_ISOM_REF_SCAL); + if (countRef > 0) + { + u32 refTrackID; + fprintf(dump, " \n"); + for (i = 1; i <= (u32) countRef; i++) + { + gf_isom_get_reference_ID(file, track, GF_ISOM_REF_SCAL, i, &refTrackID); + fprintf(dump, " \n", i, refTrackID); + } + + fprintf(dump, " \n"); + } + + fprintf(dump, " \n"); + gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT); + is_adobe_protection = gf_isom_is_adobe_protection_media(file, track, 1); + for (i=0; iDTS; + cts = dts + (s32) samp->CTS_Offset; + + fprintf(dump, " \n", i+1, dts, cts, samp->dataLength, samp->IsRAP); + if (cts\n"); + + idx = 1; + ptr = samp->data; + size = samp->dataLength; + if (is_adobe_protection) { + u8 encrypted_au = ptr[0]; + if (encrypted_au) { + fprintf(dump, " \n", i+1); + fprintf(dump, " \n\n"); + continue; + } + else { + ptr++; + size--; + } + } + while (size) { + nal_size = read_nal_size_hdr(ptr, nalh_size); + ptr += nalh_size; + + if (nalh_size + nal_size > size) { + fprintf(dump, " \n", idx, nal_size, size); + break; + } else { + fprintf(dump, " \n"); + } + idx++; + ptr+=nal_size; + size -= nal_size + nalh_size; + } + fprintf(dump, " \n"); + gf_isom_sample_del(&samp); + + fprintf(dump, "\n"); + gf_set_progress("Analysing Track NALUs", i+1, count); + } + fprintf(dump, " \n"); + fprintf(dump, "\n"); + + if (inName) gf_fclose(dump); +#ifndef GPAC_DISABLE_AV_PARSERS + if (avccfg) gf_odf_avc_cfg_del(avccfg); + if (svccfg) gf_odf_avc_cfg_del(svccfg); +#ifndef GPAC_DISABLE_HEVC + if (hevccfg) gf_odf_hevc_cfg_del(hevccfg); + if (shvccfg) gf_odf_hevc_cfg_del(shvccfg); +#endif + +#endif + gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode); +} + +#ifndef GPAC_DISABLE_ISOM_DUMP + +void dump_file_ismacryp(GF_ISOFile *file, char *inName) +{ + u32 i, j; + FILE *dump; + char szBuf[1024]; + + if (inName) { + strcpy(szBuf, inName); + strcat(szBuf, "_ismacryp.xml"); + dump = gf_fopen(szBuf, "wt"); + } else { + dump = stderr; + } + + fprintf(dump, "\n"); + fprintf(dump, "\n"); + fprintf(dump, "\n"); + + + for (i=0; i\n", gf_isom_get_track_id(file, i+1)); + for (j=0; j\n"); + } + fprintf(dump, "\n"); + if (inName) gf_fclose(dump); +} + + +void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_convert, GF_TextDumpType dump_type) +{ + FILE *dump; + GF_Err e; + u32 track; + char szBuf[1024]; + + track = gf_isom_get_track_by_id(file, trackID); + if (!track) { + fprintf(stderr, "Cannot find track ID %d\n", trackID); + return; + } + + switch (gf_isom_get_media_type(file, track)) { + case GF_ISOM_MEDIA_TEXT: + case GF_ISOM_MEDIA_SUBT: + break; + default: + fprintf(stderr, "Track ID %d is not a 3GPP text track\n", trackID); + return; + } + + if (inName) { + char *ext; + ext = ((dump_type==GF_TEXTDUMPTYPE_SVG) ? "svg" : ((dump_type==GF_TEXTDUMPTYPE_SRT) ? "srt" : "ttxt")); + if (is_convert) + sprintf(szBuf, "%s.%s", inName, ext) ; + else + sprintf(szBuf, "%s_%d_text.%s", inName, trackID, ext); + dump = gf_fopen(szBuf, "wt"); + } else { + dump = stdout; + } + e = gf_isom_text_dump(file, track, dump, dump_type); + if (inName) gf_fclose(dump); + + if (e) fprintf(stderr, "Conversion failed (%s)\n", gf_error_to_string(e)); + else fprintf(stderr, "Conversion done\n"); +} + +#endif /*GPAC_DISABLE_ISOM_DUMP*/ + +#ifndef GPAC_DISABLE_ISOM_HINTING + +void DumpSDP(GF_ISOFile *file, char *inName) +{ + const char *sdp; + u32 size, i; + FILE *dump; + char szBuf[1024]; + + if (inName) { + char *ext; + strcpy(szBuf, inName); + ext = strchr(szBuf, '.'); + if (ext) ext[0] = 0; + strcat(szBuf, "_sdp.txt"); + dump = gf_fopen(szBuf, "wt"); + } else { + dump = stderr; + fprintf(dump, "* File SDP content *\n\n"); + } + //get the movie SDP + gf_isom_sdp_get(file, &sdp, &size); + fprintf(dump, "%s", sdp); + fprintf(dump, "\r\n"); + + //then tracks + for (i=0; i365) { + y++; + d-=365; + if (y%4) d--; + } + sprintf(szDur, "%d Years %d Days, %02d:%02d:%02d.%03d", y, d, h, m, s, ms); + } + + } + return szDur; +} + +static char *format_date(u64 time, char *szTime) +{ + time_t now; + if (!time) { + strcpy(szTime, "UNKNOWN DATE"); + } else { + time -= 2082844800; + now = (u32) time; + sprintf(szTime, "GMT %s", asctime(gmtime(&now)) ); + } + return szTime; +} + +void print_udta(GF_ISOFile *file, u32 track_number) +{ + u32 i, count; + + count = gf_isom_get_udta_count(file, track_number); + if (!count) return; + + fprintf(stderr, "%d UDTA types: ", count); + + for (i=0; i0))); + switch (gf_isom_has_meta_xml(file, root_meta, tk_num)) { + case 1: + fprintf(stderr, "Meta has XML resource\n"); + break; + case 2: + fprintf(stderr, "Meta has BinaryXML resource\n"); + break; + } + if (primary_id) { + fprintf(stderr, "Primary Item - ID %d\n", primary_id); + } + for (i=0; idata, slc->size, hash); + fprintf(stderr, "\t%s#%d hash: ", szName, i+1); + for (j=0; j<20; j++) fprintf(stderr, "%02X", hash[j]); + fprintf(stderr, "\n"); + } +} + +#ifndef GPAC_DISABLE_HEVC +void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg, HEVCState *hevc_state) +{ + u32 k, idx; + fprintf(stderr, "\t%s Info: Profile %s @ Level %g - Chroma Format %d\n", hevccfg->is_shvc ? "SHVC" : "HEVC", gf_hevc_get_profile_name(hevccfg->profile_idc), ((Double)hevccfg->level_idc) / 30.0, hevccfg->chromaFormat); + fprintf(stderr, "\tNAL Unit length bits: %d - general profile compatibility 0x%08X\n", 8*hevccfg->nal_unit_size, hevccfg->general_profile_compatibility_flags); + fprintf(stderr, "\tParameter Sets: "); + for (k=0; kparam_array); k++) { + GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); + if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { + fprintf(stderr, "%d SPS ", gf_list_count(ar->nalus)); + } + if (ar->type==GF_HEVC_NALU_PIC_PARAM) { + fprintf(stderr, "%d PPS ", gf_list_count(ar->nalus)); + } + if (ar->type==GF_HEVC_NALU_VID_PARAM) { + fprintf(stderr, "%d VPS ", gf_list_count(ar->nalus)); + + for (idx=0; idxnalus); idx++) { + GF_AVCConfigSlot *vps = gf_list_get(ar->nalus, idx); + gf_media_hevc_read_vps(vps->data, vps->size, hevc_state); + } + } + } + + fprintf(stderr, "\n"); + for (k=0; kparam_array); k++) { + GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); + u32 width, height; + s32 par_n, par_d; + + if (ar->type !=GF_HEVC_NALU_SEQ_PARAM) continue; + for (idx=0; idxnalus); idx++) { + GF_AVCConfigSlot *sps = gf_list_get(ar->nalus, idx); + par_n = par_d = -1; + gf_hevc_get_sps_info_with_state(hevc_state, sps->data, sps->size, NULL, &width, &height, &par_n, &par_d); + fprintf(stderr, "\tSPS resolution %dx%d", width, height); + if ((par_n>0) && (par_d>0)) { + u32 tw, th; + gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL); + fprintf(stderr, " - Pixel Aspect Ratio %d:%d - Indicated track size %d x %d", par_n, par_d, tw, th); + } + fprintf(stderr, "\n"); + } + + } + fprintf(stderr, "\tBit Depth luma %d - Chroma %d - %d temporal layers\n", hevccfg->luma_bit_depth, hevccfg->chroma_bit_depth, hevccfg->numTemporalLayers); + if (hevccfg->is_shvc) { + fprintf(stderr, "\t%sNum Layers: %d (scalability mask 0x%02X)%s\n", hevccfg->non_hevc_base_layer ? "Non-HEVC base layer - " : "", hevccfg->num_layers, hevccfg->scalability_mask, hevccfg->complete_representation ? "" : " - no VCL data"); + } + + for (k=0; kparam_array); k++) { + GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); + if (ar->type==GF_HEVC_NALU_SEQ_PARAM) print_config_hash(ar->nalus, "SPS"); + else if (ar->type==GF_HEVC_NALU_PIC_PARAM) print_config_hash(ar->nalus, "PPS"); + else if (ar->type==GF_HEVC_NALU_VID_PARAM) print_config_hash(ar->nalus, "VPS"); + } +} +#endif + + +void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) +{ + Float scale; + Bool is_od_track = 0; + u32 trackNum, i, j, max_rate, rate, ts, mtype, msub_type, timescale, sr, nb_ch, count, alt_group, nb_groups, nb_edits; + u64 time_slice, dur, size; + u8 bps; + GF_ESD *esd; + char szDur[50]; + char *lang; + + trackNum = gf_isom_get_track_by_id(file, trackID); + if (!trackNum) { + fprintf(stderr, "No track with ID %d found\n", trackID); + return; + } + + timescale = gf_isom_get_media_timescale(file, trackNum); + fprintf(stderr, "Track # %d Info - TrackID %d - TimeScale %d - Media Duration %s\n", trackNum, trackID, timescale, format_duration(gf_isom_get_media_duration(file, trackNum), timescale, szDur)); + nb_edits = gf_isom_get_edit_segment_count(file, trackNum); + if (nb_edits) + fprintf(stderr, "Track has %d edit lists: track duration is %s\n", nb_edits, format_duration(gf_isom_get_track_duration(file, trackNum), gf_isom_get_timescale(file), szDur)); + + if (gf_isom_is_track_in_root_od(file, trackNum) ) fprintf(stderr, "Track is present in Root OD\n"); + if (!gf_isom_is_track_enabled(file, trackNum)) fprintf(stderr, "Track is disabled\n"); + gf_isom_get_media_language(file, trackNum, &lang); + fprintf(stderr, "Media Info: Language \"%s (%s)\" - ", GetLanguage(lang), lang ); + gf_free(lang); + mtype = gf_isom_get_media_type(file, trackNum); + fprintf(stderr, "Type \"%s:", gf_4cc_to_str(mtype)); + msub_type = gf_isom_get_mpeg4_subtype(file, trackNum, 1); + if (!msub_type) msub_type = gf_isom_get_media_subtype(file, trackNum, 1); + fprintf(stderr, "%s\" - %d samples\n", gf_4cc_to_str(msub_type), gf_isom_get_sample_count(file, trackNum)); + + count = gf_isom_get_track_kind_count(file, trackNum); + for (i = 0; i < count; i++) { + char *kind_scheme, *kind_value; + gf_isom_get_track_kind(file, trackNum, i, &kind_scheme, &kind_value); + fprintf(stderr, "Kind: %s - %s\n", kind_scheme, kind_value); + } + + if (gf_isom_is_track_fragmented(file, trackID) ) { + u32 frag_samples; + u64 frag_duration; + gf_isom_get_fragmented_samples_info(file, trackID, &frag_samples, &frag_duration); + fprintf(stderr, "Fragmented track: %d samples - Media Duration %s\n", frag_samples, format_duration(frag_duration, timescale, szDur)); + } + + if (!gf_isom_is_self_contained(file, trackNum, 1)) { + const char *url, *urn; + gf_isom_get_data_reference(file, trackNum, 1, &url, &urn); + fprintf(stderr, "Media Data Location: %s\n", url ? url : urn); + } + + if (full_dump) { + const char *handler_name; + gf_isom_get_handler_name(file, trackNum, &handler_name); + fprintf(stderr, "Handler name: %s\n", handler_name); + } + + print_udta(file, trackNum); + + if (mtype==GF_ISOM_MEDIA_VISUAL) { + s32 tx, ty; + u32 w, h; + gf_isom_get_track_layout_info(file, trackNum, &w, &h, &tx, &ty, NULL); + fprintf(stderr, "Visual Track layout: x=%d y=%d width=%d height=%d\n", tx, ty, w, h); + } + + gf_isom_get_audio_info(file, trackNum, 1, &sr, &nb_ch, &bps); + gf_isom_set_nalu_extract_mode(file, trackNum, GF_ISOM_NALU_EXTRACT_INSPECT); + + msub_type = gf_isom_get_media_subtype(file, trackNum, 1); + if ((msub_type==GF_ISOM_SUBTYPE_MPEG4) + || (msub_type==GF_ISOM_SUBTYPE_MPEG4_CRYP) + || (msub_type==GF_ISOM_SUBTYPE_AVC_H264) + || (msub_type==GF_ISOM_SUBTYPE_AVC2_H264) + || (msub_type==GF_ISOM_SUBTYPE_AVC3_H264) + || (msub_type==GF_ISOM_SUBTYPE_AVC4_H264) + || (msub_type==GF_ISOM_SUBTYPE_SVC_H264) + || (msub_type==GF_ISOM_SUBTYPE_LSR1) + || (msub_type==GF_ISOM_SUBTYPE_HVC1) + || (msub_type==GF_ISOM_SUBTYPE_HEV1) + || (msub_type==GF_ISOM_SUBTYPE_SHV1) + || (msub_type==GF_ISOM_SUBTYPE_SHC1) + || (msub_type==GF_ISOM_SUBTYPE_HVT1) + ) { + esd = gf_isom_get_esd(file, trackNum, 1); + if (!esd) { + fprintf(stderr, "WARNING: Broken MPEG-4 Track\n"); + } else { + const char *st = gf_odf_stream_type_name(esd->decoderConfig->streamType); + if (st) { + fprintf(stderr, "MPEG-4 Config%s%s Stream - ObjectTypeIndication 0x%02x\n", + full_dump ? "\n\t" : ": ", st, esd->decoderConfig->objectTypeIndication); + } else { + fprintf(stderr, "MPEG-4 Config%sStream Type 0x%02x - ObjectTypeIndication 0x%02x\n", + full_dump ? "\n\t" : ": ", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication); + } + if (esd->decoderConfig->streamType==GF_STREAM_OD) + is_od_track=1; + + if (esd->decoderConfig->streamType==GF_STREAM_VISUAL) { + u32 w, h; + u16 rvc_predef; + w = h = 0; + if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_MPEG4_PART2) { +#ifndef GPAC_DISABLE_AV_PARSERS + if (!esd->decoderConfig->decoderSpecificInfo) { +#else + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + fprintf(stderr, "MPEG-4 Visual Size %d x %d\n", w, h); +#endif + fprintf(stderr, "\tNon-compliant MPEG-4 Visual track: video_object_layer infos not found in sample description\n"); +#ifndef GPAC_DISABLE_AV_PARSERS + } else { + GF_M4VDecSpecInfo dsi; + gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); + if (full_dump) fprintf(stderr, "\t"); + w = dsi.width; + h = dsi.height; + fprintf(stderr, "MPEG-4 Visual Size %d x %d - %s\n", w, h, gf_m4v_get_profile_name(dsi.VideoPL)); + if (dsi.par_den && dsi.par_num) { + u32 tw, th; + gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL); + fprintf(stderr, "Pixel Aspect Ratio %d:%d - Indicated track size %d x %d\n", dsi.par_num, dsi.par_den, tw, th); + } + } +#endif + } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) { +#ifndef GPAC_DISABLE_AV_PARSERS + GF_AVCConfig *avccfg, *svccfg; + GF_AVCConfigSlot *slc; + s32 par_n, par_d; +#endif + + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + if (full_dump) fprintf(stderr, "\t"); + fprintf(stderr, "AVC/H264 Video - Visual Size %d x %d\n", w, h); +#ifndef GPAC_DISABLE_AV_PARSERS + avccfg = gf_isom_avc_config_get(file, trackNum, 1); + svccfg = gf_isom_svc_config_get(file, trackNum, 1); + if (!avccfg && !svccfg) { + fprintf(stderr, "\n\n\tNon-compliant AVC track: SPS/PPS not found in sample description\n"); + } else if (avccfg) { + fprintf(stderr, "\tAVC Info: %d SPS - %d PPS", gf_list_count(avccfg->sequenceParameterSets) , gf_list_count(avccfg->pictureParameterSets) ); + fprintf(stderr, " - Profile %s @ Level %g\n", gf_avc_get_profile_name(avccfg->AVCProfileIndication), ((Double)avccfg->AVCLevelIndication)/10.0 ); + fprintf(stderr, "\tNAL Unit length bits: %d\n", 8*avccfg->nal_unit_size); + for (i=0; isequenceParameterSets); i++) { + slc = gf_list_get(avccfg->sequenceParameterSets, i); + gf_avc_get_sps_info(slc->data, slc->size, NULL, NULL, NULL, &par_n, &par_d); + if ((par_n>0) && (par_d>0)) { + u32 tw, th; + gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL); + fprintf(stderr, "\tPixel Aspect Ratio %d:%d - Indicated track size %d x %d\n", par_n, par_d, tw, th); + } + if (!full_dump) break; + } + if (avccfg->chroma_bit_depth) { + fprintf(stderr, "\tChroma format %d - Luma bit depth %d - chroma bit depth %d\n", avccfg->chroma_format, avccfg->luma_bit_depth, avccfg->chroma_bit_depth); + } + + print_config_hash(avccfg->sequenceParameterSets, "SPS"); + print_config_hash(avccfg->pictureParameterSets, "PPS"); + + gf_odf_avc_cfg_del(avccfg); + } + if (svccfg) { + fprintf(stderr, "\n\tSVC Info: %d SPS - %d PPS - Profile %s @ Level %g\n", gf_list_count(svccfg->sequenceParameterSets) , gf_list_count(svccfg->pictureParameterSets), gf_avc_get_profile_name(svccfg->AVCProfileIndication), ((Double)svccfg->AVCLevelIndication)/10.0 ); + fprintf(stderr, "\tSVC NAL Unit length bits: %d\n", 8*svccfg->nal_unit_size); + for (i=0; isequenceParameterSets); i++) { + slc = gf_list_get(svccfg->sequenceParameterSets, i); + if (slc) { + u32 s_w, s_h, sps_id; + gf_avc_get_sps_info(slc->data, slc->size, &sps_id, &s_w, &s_h, &par_n, &par_d); + fprintf(stderr, "\t\tSSPS ID %d - Visual Size %d x %d\n", sps_id, s_w, s_h); + if ((par_n>0) && (par_d>0)) { + u32 tw, th; + gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL); + fprintf(stderr, "\tPixel Aspect Ratio %d:%d - Indicated track size %d x %d\n", par_n, par_d, tw, th); + } + } + } + print_config_hash(svccfg->sequenceParameterSets, "SPS"); + print_config_hash(svccfg->pictureParameterSets, "PPS"); + print_config_hash(svccfg->sequenceParameterSetExtensions, "SPSEx"); + + gf_odf_avc_cfg_del(svccfg); + } +#endif /*GPAC_DISABLE_AV_PARSERS*/ + + } else if ((esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_HEVC) + || (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_SHVC) + ) { +#if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC) + HEVCState hevc_state; + GF_HEVCConfig *hevccfg, *shvccfg; + memset(&hevc_state, 0, sizeof(HEVCState)); + hevc_state.sps_active_idx = -1; +#endif + + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + if (full_dump) fprintf(stderr, "\t"); + fprintf(stderr, "HEVC Video - Visual Size %d x %d\n", w, h); +#if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC) + hevccfg = gf_isom_hevc_config_get(file, trackNum, 1); + shvccfg = gf_isom_shvc_config_get(file, trackNum, 1); + + if (msub_type==GF_ISOM_SUBTYPE_HVT1) { + const char *data; + u32 size; + u32 is_default, x,y,w,h, id, independent; + Bool full_frame; + if (gf_isom_get_tile_info(file, trackNum, 1, &is_default, &id, &independent, &full_frame, &x, &y, &w, &h)) { + fprintf(stderr, "\tHEVC Tile - ID %d independent %d (x,y,w,h)=%d,%d,%d,%d \n", id, independent, x, y, w, h); + } else if (gf_isom_get_sample_group_info(file, trackNum, 1, GF_4CC('t','r','i','f'), &is_default, &data, &size)) { + fprintf(stderr, "\tHEVC Tile track containing a tile set\n"); + } else { + fprintf(stderr, "\tHEVC Tile track without tiling info\n"); + } + } else if (!hevccfg && !shvccfg) { + fprintf(stderr, "\n\n\tNon-compliant HEVC track: No hvcC or shcC found in sample description\n"); + } + if (hevccfg) { + dump_hevc_track_info(file, trackNum, hevccfg, &hevc_state); + gf_odf_hevc_cfg_del(hevccfg); + fprintf(stderr, "\n"); + } + if (shvccfg) { + dump_hevc_track_info(file, trackNum, shvccfg, &hevc_state); + gf_odf_hevc_cfg_del(shvccfg); + } +#endif /*GPAC_DISABLE_AV_PARSERS && defined(GPAC_DISABLE_HEVC)*/ + } + + /*OGG media*/ + else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_MEDIA_OGG) { + char *szName; + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + if (full_dump) fprintf(stderr, "\t"); + if (!strnicmp(&esd->decoderConfig->decoderSpecificInfo->data[3], "theora", 6)) szName = "Theora"; + else szName = "Unknown"; + fprintf(stderr, "Ogg/%s video / GPAC Mux - Visual Size %d x %d\n", szName, w, h); + } + else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_IMAGE_JPEG) { + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + fprintf(stderr, "JPEG Stream - Visual Size %d x %d\n", w, h); + } + else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_IMAGE_PNG) { + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + fprintf(stderr, "PNG Stream - Visual Size %d x %d\n", w, h); + } + else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_IMAGE_JPEG_2000) { + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + fprintf(stderr, "JPEG2000 Stream - Visual Size %d x %d\n", w, h); + } + if (!w || !h) { + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + if (full_dump) fprintf(stderr, "\t"); + fprintf(stderr, "Visual Size %d x %d\n", w, h); + } + if (gf_isom_get_rvc_config(file, trackNum, 1, &rvc_predef, NULL, NULL, NULL)==GF_OK) { + fprintf(stderr, "Has RVC signaled - Predefined configuration %d\n", rvc_predef); + } + + } else if (esd->decoderConfig->streamType==GF_STREAM_AUDIO) { +#ifndef GPAC_DISABLE_AV_PARSERS + GF_M4ADecSpecInfo a_cfg; + GF_Err e; + u32 oti; +#endif + u32 is_mp2 = 0; + switch (esd->decoderConfig->objectTypeIndication) { + case GPAC_OTI_AUDIO_AAC_MPEG2_MP: + case GPAC_OTI_AUDIO_AAC_MPEG2_LCP: + case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP: + is_mp2 = 1; + case GPAC_OTI_AUDIO_AAC_MPEG4: +#ifndef GPAC_DISABLE_AV_PARSERS + if (!esd->decoderConfig->decoderSpecificInfo) + e = GF_NON_COMPLIANT_BITSTREAM; + else + e = gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg); + if (full_dump) fprintf(stderr, "\t"); + if (e) fprintf(stderr, "Corrupted AAC Config\n"); + else { + fprintf(stderr, "%s - %d Channel(s) - SampleRate %d", gf_m4a_object_type_name(a_cfg.base_object_type), a_cfg.nb_chan, a_cfg.base_sr); + if (is_mp2) fprintf(stderr, " (MPEG-2 Signaling)"); + if (a_cfg.has_sbr) fprintf(stderr, " - SBR SampleRate %d", a_cfg.sbr_sr); + if (a_cfg.has_ps) fprintf(stderr, " - PS"); + fprintf(stderr, "\n"); + } +#else + fprintf(stderr, "MPEG-2/4 Audio - %d Channels - SampleRate %d\n", nb_ch, sr); +#endif + break; + case GPAC_OTI_AUDIO_MPEG2_PART3: + case GPAC_OTI_AUDIO_MPEG1: + if (msub_type == GF_ISOM_SUBTYPE_MPEG4_CRYP) { + fprintf(stderr, "MPEG-1/2 Audio - %d Channels - SampleRate %d\n", nb_ch, sr); + } else { +#ifndef GPAC_DISABLE_AV_PARSERS + GF_ISOSample *samp = gf_isom_get_sample(file, trackNum, 1, &oti); + if (samp) { + oti = GF_4CC((u8)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]); + if (full_dump) fprintf(stderr, "\t"); + fprintf(stderr, "%s Audio - %d Channel(s) - SampleRate %d - Layer %d\n", + gf_mp3_version_name(oti), + gf_mp3_num_channels(oti), + gf_mp3_sampling_rate(oti), + gf_mp3_layer(oti) + ); + gf_isom_sample_del(&samp); + } else { + fprintf(stderr, "\n\tError fetching sample: %s\n", gf_error_to_string(gf_isom_last_error(file)) ); + } +#else + fprintf(stderr, "MPEG-1/2 Audio - %d Channels - SampleRate %d\n", nb_ch, sr); +#endif + } + break; + /*OGG media*/ + case GPAC_OTI_MEDIA_OGG: + { + char *szName; + if (full_dump) fprintf(stderr, "\t"); + if (!strnicmp(&esd->decoderConfig->decoderSpecificInfo->data[3], "vorbis", 6)) szName = "Vorbis"; + else if (!strnicmp(&esd->decoderConfig->decoderSpecificInfo->data[2], "Speex", 5)) szName = "Speex"; + else if (!strnicmp(&esd->decoderConfig->decoderSpecificInfo->data[2], "Flac", 4)) szName = "Flac"; + else szName = "Unknown"; + fprintf(stderr, "Ogg/%s audio / GPAC Mux - Sample Rate %d - %d channel(s)\n", szName, sr, nb_ch); + } + break; + case GPAC_OTI_AUDIO_EVRC_VOICE: + fprintf(stderr, "EVRC Audio - Sample Rate 8000 - 1 channel\n"); + break; + case GPAC_OTI_AUDIO_SMV_VOICE: + fprintf(stderr, "SMV Audio - Sample Rate 8000 - 1 channel\n"); + break; + case GPAC_OTI_AUDIO_13K_VOICE: + fprintf(stderr, "QCELP Audio - Sample Rate 8000 - 1 channel\n"); + break; + /*packetVideo hack for EVRC...*/ + case 0xD1: + if (esd->decoderConfig->decoderSpecificInfo && (esd->decoderConfig->decoderSpecificInfo->dataLength==8) + && !strnicmp(esd->decoderConfig->decoderSpecificInfo->data, "pvmm", 4)) { + if (full_dump) fprintf(stderr, "\t"); + fprintf(stderr, "EVRC Audio (PacketVideo Mux) - Sample Rate 8000 - 1 channel\n"); + } + break; + } + } + else if (esd->decoderConfig->streamType==GF_STREAM_SCENE) { + if (esd->decoderConfig->objectTypeIndication<=4) { + GF_BIFSConfig *b_cfg = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication); + fprintf(stderr, "BIFS Scene description - %s stream\n", b_cfg->elementaryMasks ? "Animation" : "Command"); + if (full_dump && !b_cfg->elementaryMasks) { + fprintf(stderr, "\tWidth %d Height %d Pixel Metrics %s\n", b_cfg->pixelWidth, b_cfg->pixelHeight, b_cfg->pixelMetrics ? "yes" : "no"); + } + gf_odf_desc_del((GF_Descriptor *)b_cfg); + } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_SCENE_AFX) { + u8 tag = esd->decoderConfig->decoderSpecificInfo ? esd->decoderConfig->decoderSpecificInfo->data[0] : 0xFF; + const char *afxtype = gf_afx_get_type_description(tag); + fprintf(stderr, "AFX Stream - type %s (%d)\n", afxtype, tag); + } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_FONT) { + fprintf(stderr, "Font Data stream\n"); + } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_SCENE_LASER) { + GF_LASERConfig l_cfg; + gf_odf_get_laser_config(esd->decoderConfig->decoderSpecificInfo, &l_cfg); + fprintf(stderr, "LASER Stream - %s\n", l_cfg.newSceneIndicator ? "Full Scene" : "Scene Segment"); + } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_TEXT_MPEG4) { + fprintf(stderr, "MPEG-4 Streaming Text stream\n"); + } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_SCENE_SYNTHESIZED_TEXTURE) { + fprintf(stderr, "Synthetized Texture stream stream\n"); + } else { + fprintf(stderr, "Unknown Systems stream OTI %d\n", esd->decoderConfig->objectTypeIndication); + } + } + + /*sync is only valid if we open all tracks to take care of default MP4 sync..*/ + if (!full_dump) { + if (!esd->OCRESID || (esd->OCRESID == esd->ESID)) + fprintf(stderr, "Self-synchronized\n"); + else + fprintf(stderr, "Synchronized on stream %d\n", esd->OCRESID); + } else { + fprintf(stderr, "\tDecoding Buffer size %d - Bitrate: avg %d - max %d kbps\n", esd->decoderConfig->bufferSizeDB, esd->decoderConfig->avgBitrate/1000, esd->decoderConfig->maxBitrate/1000); + if (esd->dependsOnESID) + fprintf(stderr, "\tDepends on stream %d for decoding\n", esd->dependsOnESID); + else + fprintf(stderr, "\tNo stream dependencies for decoding\n"); + + fprintf(stderr, "\tStreamPriority %d\n", esd->streamPriority); + if (esd->URLString) fprintf(stderr, "\tRemote Data Source %s\n", esd->URLString); + } + gf_odf_desc_del((GF_Descriptor *) esd); + + /*ISMACryp*/ + if (msub_type == GF_ISOM_SUBTYPE_MPEG4_CRYP) { + const char *scheme_URI, *KMS_URI; + u32 scheme_type, version; + u32 IV_size; + Bool use_sel_enc; + + if (gf_isom_is_ismacryp_media(file, trackNum, 1)) { + gf_isom_get_ismacryp_info(file, trackNum, 1, NULL, &scheme_type, &version, &scheme_URI, &KMS_URI, &use_sel_enc, &IV_size, NULL); + fprintf(stderr, "\n*Encrypted stream - ISMA scheme %s (version %d)\n", gf_4cc_to_str(scheme_type), version); + if (scheme_URI) fprintf(stderr, "scheme location: %s\n", scheme_URI); + if (KMS_URI) { + if (!strnicmp(KMS_URI, "(key)", 5)) fprintf(stderr, "KMS location: key in file\n"); + else fprintf(stderr, "KMS location: %s\n", KMS_URI); + } + fprintf(stderr, "Selective Encryption: %s\n", use_sel_enc ? "Yes" : "No"); + if (IV_size) fprintf(stderr, "Initialization Vector size: %d bits\n", IV_size*8); + } else if (gf_isom_is_omadrm_media(file, trackNum, 1)) { + const char *textHdrs; + u32 enc_type, hdr_len; + u64 orig_len; + fprintf(stderr, "\n*Encrypted stream - OMA DRM\n"); + gf_isom_get_omadrm_info(file, trackNum, 1, NULL, NULL, NULL, &scheme_URI, &KMS_URI, &textHdrs, &hdr_len, &orig_len, &enc_type, &use_sel_enc, &IV_size, NULL); + fprintf(stderr, "Rights Issuer: %s\n", KMS_URI); + fprintf(stderr, "Content ID: %s\n", scheme_URI); + if (textHdrs) { + u32 i, offset; + const char *start = textHdrs; + fprintf(stderr, "OMA Textual Headers:\n"); + i=offset=0; + while (istreams[0].acmod); + for (i=0; istreams[0].nb_dep_sub; ++i) { + assert(ac3->streams[0].nb_dep_sub == 1); + nb_ch += gf_ac3_get_channels(ac3->streams[0].chan_loc); + } + lfe = ac3->streams[0].lfon; + br = ac3->is_ec3 ? ac3->brcode : gf_ac3_get_bitrate(ac3->brcode); + is_ec3 = ac3->is_ec3; + gf_free(ac3); + } +#endif + fprintf(stderr, "\t%s stream - Sample Rate %d - %d%s channel(s) - bitrate %d\n", is_ec3 ? "EC-3" : "AC-3", sr, nb_ch, lfe ? ".1" : "", br); + } else if (msub_type == GF_ISOM_SUBTYPE_3GP_SMV) { + fprintf(stderr, "\t3GPP SMV stream - Sample Rate %d - %d channel(s) %d bits per samples\n", sr, nb_ch, (u32) bps); + } else if (msub_type == GF_ISOM_SUBTYPE_3GP_DIMS) { + u32 w, h; + GF_DIMSDescription dims; + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + + gf_isom_get_dims_description(file, trackNum, 1, &dims); + fprintf(stderr, "\t3GPP DIMS stream - size %d x %d - Profile %d - Level %d\n", w, h, dims.profile, dims.level); + fprintf(stderr, "\tpathComponents: %d - useFullRequestHost: %s\n", dims.pathComponents, dims.fullRequestHost ? "yes" : "no"); + fprintf(stderr, "\tstream type: %s - redundant: %s\n", dims.streamType ? "primary" : "secondary", (dims.containsRedundant==1) ? "main" : ((dims.containsRedundant==2) ? "redundant" : "main+redundant") ); + if (dims.textEncoding[0]) fprintf(stderr, "\ttext encoding %s\n", dims.textEncoding); + if (dims.contentEncoding[0]) fprintf(stderr, "\tcontent encoding %s\n", dims.contentEncoding); + if (dims.content_script_types) fprintf(stderr, "\tscript languages %s\n", dims.content_script_types); + } else if (mtype==GF_ISOM_MEDIA_HINT) { + u32 refTrack; + s32 i, refCount = gf_isom_get_reference_count(file, trackNum, GF_ISOM_REF_HINT); + if (refCount) { + fprintf(stderr, "Streaming Hint Track for track%s ", (refCount>1) ? "s" :""); + for (i=0; icompressor_name, udesc->width, udesc->height); + } else if (mtype==GF_ISOM_MEDIA_AUDIO) { + fprintf(stderr, "Audio Track - Sample Rate %d - %d channel(s)\n", udesc->samplerate, udesc->nb_channels); + } else { + fprintf(stderr, "Unknown media type\n"); + } + if (udesc->vendor_code) + fprintf(stderr, "\tVendor code \"%s\" - Version %d - revision %d\n", gf_4cc_to_str(udesc->vendor_code), udesc->version, udesc->revision); + + if (udesc->extension_buf) { + fprintf(stderr, "\tCodec configuration data size: %d bytes\n", udesc->extension_buf_size); + gf_free(udesc->extension_buf); + } + gf_free(udesc); + } else { + fprintf(stderr, "Unknown track type\n"); + } + } + + { + char szCodec[100]; + gf_media_get_rfc_6381_codec_name(file, trackNum, szCodec, GF_FALSE, GF_FALSE); + fprintf(stderr, "\tRFC6381 Codec Parameters: %s\n", szCodec); + } + + DumpMetaItem(file, 0, trackNum, "Track Meta"); + + gf_isom_get_track_switch_group_count(file, trackNum, &alt_group, &nb_groups); + if (alt_group) { + fprintf(stderr, "Alternate Group ID %d\n", alt_group); + for (i=0; iDTS+samp->CTS_Offset; + size += samp->dataLength; + rate += samp->dataLength; + if (samp->DTS - time_slice>ts) { + if (max_rate < rate) max_rate = rate; + rate = 0; + time_slice = samp->DTS; + } + gf_isom_sample_del(&samp); + } + fprintf(stderr, "\nComputed info from media:\n"); + scale = 1000; + scale /= ts; + dur = (u64) (scale * (s64)dur); + fprintf(stderr, "\tTotal size "LLU" bytes - Total samples duration "LLU" ms\n", size, dur); + if (!dur) { + fprintf(stderr, "\n"); + return; + } + /*rate in byte, dur is in ms*/ + rate = (u32) ((size * 8 * 1000) / dur); + max_rate *= 8; + if (rate >= 1500) { + rate /= 1000; + max_rate /= 1000; + fprintf(stderr, "\tAverage rate %d kbps - Max Rate %d kbps\n", rate, max_rate); + } else { + fprintf(stderr, "\tAverage rate %d bps - Max Rate %d bps\n", rate, max_rate); + } + + { + u32 dmin, dmax, davg, smin, smax, savg; + gf_isom_get_chunks_infos(file, trackNum, &dmin, &davg, &dmax, &smin, &savg, &smax); + fprintf(stderr, "\tChunk durations: min %d ms - max %d ms - average %d ms\n", (1000*dmin)/ts, (1000*dmax)/ts, (1000*davg)/ts); + fprintf(stderr, "\tChunk sizes (bytes): min %d - max %d - average %d\n", smin, smax, savg); + } + fprintf(stderr, "\n"); + + count = gf_isom_get_chapter_count(file, trackNum); + if (count) { + char szDur[20]; + const char *name; + u64 time; + fprintf(stderr, "\nChapters:\n"); + for (j=0; j0) && (tag <= (sizeof(ID3v1Genres)/sizeof(const char *)) )) { + return ID3v1Genres[tag-1]; + } + return "Unknown"; +} +u32 id3_get_genre_tag(const char *name) +{ + u32 i, count = sizeof(ID3v1Genres)/sizeof(const char *); + if (!name) return 0; + for (i=0; itag == GF_ODF_IOD_TAG) { + fprintf(stderr, "File has root IOD (%d bytes)\n", desc_size); + fprintf(stderr, "Scene PL 0x%02x - Graphics PL 0x%02x - OD PL 0x%02x\n", iod->scene_profileAndLevel, iod->graphics_profileAndLevel, iod->OD_profileAndLevel); + fprintf(stderr, "Visual PL: %s (0x%02x)\n", gf_m4v_get_profile_name(iod->visual_profileAndLevel), iod->visual_profileAndLevel); + fprintf(stderr, "Audio PL: %s (0x%02x)\n", gf_m4a_get_profile_name(iod->audio_profileAndLevel), iod->audio_profileAndLevel); + //fprintf(stderr, "inline profiles included %s\n", iod->inlineProfileFlag ? "yes" : "no"); + } else { + fprintf(stderr, "File has root OD (%d bytes)\n", desc_size); + } + if (!gf_list_count(iod->ESDescriptors)) fprintf(stderr, "No streams included in root OD\n"); + gf_odf_desc_del((GF_Descriptor *) iod); + } else { + fprintf(stderr, "File has no MPEG4 IOD/OD\n"); + } + if (gf_isom_is_JPEG2000(file)) fprintf(stderr, "File is JPEG 2000\n"); + + count = gf_isom_get_copyright_count(file); + if (count) { + const char *lang, *note; + fprintf(stderr, "\nCopyrights:\n"); + for (i=0; i>31) fprintf(stderr, "\tCover Art: PNG File\n"); + else fprintf(stderr, "\tCover Art: JPEG File\n"); + } + } + + print_udta(file, 0); + fprintf(stderr, "\n"); + for (i=0; iuser; + + switch (evt_type) { + case GF_M2TS_EVT_PAT_FOUND: + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, 0); + } + break; + case GF_M2TS_EVT_PAT_UPDATE: + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, 0); + } + break; + case GF_M2TS_EVT_PAT_REPEAT: + /* WARNING: We detect the pat on a repetition, probably to ensure that we also have seen all the PMT + To be checked */ + dumper->has_seen_pat = 1; + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, 0); + } +// fprintf(stderr, "Repeated PAT found - %d programs\n", gf_list_count(ts->programs) ); + break; + case GF_M2TS_EVT_CAT_FOUND: + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, 0); + } + break; + case GF_M2TS_EVT_CAT_UPDATE: + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, 0); + } + break; + case GF_M2TS_EVT_CAT_REPEAT: + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, 0); + } + break; + case GF_M2TS_EVT_PMT_FOUND: + prog = (GF_M2TS_Program*)par; + if (gf_list_count(ts->programs)>1 && prog->number!=dumper->prog_number) + break; + + count = gf_list_count(prog->streams); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Program number %d found - %d streams:\n", prog->number, count)); + for (i=0; istreams, i); + if (es->pid == prog->pmt_pid) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\tPID %d: Program Map Table\n", es->pid)); + } else { + GF_M2TS_PES *pes = (GF_M2TS_PES *)es; + gf_m2ts_set_pes_framing(pes, dumper->pes_out ? GF_M2TS_PES_FRAMING_RAW : GF_M2TS_PES_FRAMING_DEFAULT); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\tPID %d: %s ", pes->pid, gf_m2ts_get_stream_name(pes->stream_type) )); + if (pes->mpeg4_es_id) GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, (" - MPEG-4 ES ID %d", pes->mpeg4_es_id)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\n")); + } + } + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, prog->pmt_pid); + } + break; + case GF_M2TS_EVT_PMT_UPDATE: + prog = (GF_M2TS_Program*)par; + if (gf_list_count(ts->programs)>1 && prog->number!=dumper->prog_number) + break; + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, prog->pmt_pid); + } + break; + case GF_M2TS_EVT_PMT_REPEAT: + prog = (GF_M2TS_Program*)par; + if (gf_list_count(ts->programs)>1 && prog->number!=dumper->prog_number) + break; + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\n", ts->pck_number, prog->pmt_pid); + } + break; + case GF_M2TS_EVT_SDT_FOUND: + count = gf_list_count(ts->SDTs) ; + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Program Description found - %d desc:\n", count)); + for (i=0; iSDTs, i); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\tServiceID %d - Provider %s - Name %s\n", sdt->service_id, sdt->provider, sdt->service)); + } + break; + case GF_M2TS_EVT_SDT_UPDATE: + count = gf_list_count(ts->SDTs) ; + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Program Description updated - %d desc\n", count)); + for (i=0; iSDTs, i); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\tServiceID %d - Provider %s - Name %s\n", sdt->service_id, sdt->provider, sdt->service)); + } + break; + case GF_M2TS_EVT_SDT_REPEAT: + break; + case GF_M2TS_EVT_PES_TIMING: + pck = par; + if (gf_list_count(ts->programs)>1 && pck->stream->program->number != dumper->prog_number) + break; + + break; + case GF_M2TS_EVT_PES_PCK: + pck = par; + if (gf_list_count(ts->programs)>1 && pck->stream->program->number != dumper->prog_number) + break; + if (dumper->has_seen_pat) { + + /*We need the interpolated PCR for the pcrb, hence moved this calculus out, and saving the calculated value in index_info to put it in the pcrb*/ + GF_M2TS_PES *pes = pck->stream; + /*FIXME : not used GF_M2TS_Program *prog = pes->program; */ + /* Interpolated PCR value for the TS packet containing the PES header start */ + u64 interpolated_pcr_value = 0; + if (pes->last_pcr_value && pes->before_last_pcr_value_pck_number && pes->last_pcr_value > pes->before_last_pcr_value) { + u32 delta_pcr_pck_num = pes->last_pcr_value_pck_number - pes->before_last_pcr_value_pck_number; + u32 delta_pts_pcr_pck_num = pes->pes_start_packet_number - pes->last_pcr_value_pck_number; + u64 delta_pcr_value = pes->last_pcr_value - pes->before_last_pcr_value; + if ((pes->pes_start_packet_number > pes->last_pcr_value_pck_number) + && (pes->last_pcr_value > pes->before_last_pcr_value)) { + + pes->last_pcr_value = pes->before_last_pcr_value; + } + /* we can compute the interpolated pcr value for the packet containing the PES header */ + interpolated_pcr_value = pes->last_pcr_value + (u64)((delta_pcr_value*delta_pts_pcr_pck_num*1.0)/delta_pcr_pck_num); + } + + if (dumper->timestamps_info_file) { + Double diff; + fprintf(dumper->timestamps_info_file, "%u\t%d\t", pck->stream->pes_start_packet_number, pck->stream->pid); + if (interpolated_pcr_value) fprintf(dumper->timestamps_info_file, "%f", interpolated_pcr_value/(300.0 * 90000)); + fprintf(dumper->timestamps_info_file, "\t"); + if (pck->DTS) fprintf(dumper->timestamps_info_file, "%f", (pck->DTS / 90000.0)); + fprintf(dumper->timestamps_info_file, "\t%f\t%d\t%d", pck->PTS / 90000.0, (pck->flags & GF_M2TS_PES_PCK_RAP ? 1 : 0), (pck->flags & GF_M2TS_PES_PCK_DISCONTINUITY ? 1 : 0)); + if (interpolated_pcr_value) { + diff = (pck->DTS ? pck->DTS : pck->PTS) / 90000.0; + diff -= pes->last_pcr_value / (300.0 * 90000); + fprintf(dumper->timestamps_info_file, "\t%f\n", diff); + if (diff<0) fprintf(stderr, "Warning: detected PTS/DTS value less than current PCR of %g sec\n", diff); + } else { + fprintf(dumper->timestamps_info_file, "\t\n"); + } + } + } + + if (dumper->has_seen_pat && dumper->pes_out && (dumper->dump_pid == pck->stream->pid)) { + gf_fwrite(pck->data, pck->data_len, 1, dumper->pes_out); + } + break; + case GF_M2TS_EVT_PES_PCR: + pck = par; + if (gf_list_count(ts->programs)>1 && pck->stream->program->number != dumper->prog_number) + break; + if (dumper->timestamps_info_file) { + fprintf(dumper->timestamps_info_file, "%u\t%d\t%f\t\t\t\t%d\n", pck->stream->program->last_pcr_value_pck_number, pck->stream->pid, pck->PTS / (300*90000.0), (pck->flags & GF_M2TS_PES_PCK_DISCONTINUITY ? 1 : 0)); + } + break; + case GF_M2TS_EVT_SL_PCK: +#if 0 + { + GF_M2TS_SL_PCK *sl_pck = par; + if (dumper->pes_out && (dumper->dump_pid == sl_pck->stream->pid)) { + GF_SLHeader header; + u32 header_len; + if (sl_pck->stream->mpeg4_es_id) { + GF_ESD *esd = ((GF_M2TS_PES*)sl_pck->stream)->esd; + if (!dumper->is_info_dumped) { + if (esd->decoderConfig->decoderSpecificInfo) gf_fwrite(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, 1, dumper->pes_out_info); + dumper->is_info_dumped = 1; + fprintf(dumper->pes_out_nhml, "pes_out_nhml, "timeScale=\"%d\" ", esd->slConfig->timestampResolution); + fprintf(dumper->pes_out_nhml, "streamType=\"%d\" ", esd->decoderConfig->streamType); + fprintf(dumper->pes_out_nhml, "objectTypeIndication=\"%d\" ", esd->decoderConfig->objectTypeIndication); + if (esd->decoderConfig->decoderSpecificInfo) fprintf(dumper->pes_out_nhml, "specificInfoFile=\"%s\" ", dumper->info); + fprintf(dumper->pes_out_nhml, "baseMediaFile=\"%s\" ", dumper->dump); + fprintf(dumper->pes_out_nhml, "inRootOD=\"yes\">\n"); + } + gf_sl_depacketize(esd->slConfig, &header, sl_pck->data, sl_pck->data_len, &header_len); + gf_fwrite(sl_pck->data+header_len, sl_pck->data_len-header_len, 1, dumper->pes_out); + fprintf(dumper->pes_out_nhml, "\n", LLD_CAST header.decodingTimeStamp, sl_pck->data_len-header_len, (header.randomAccessPointFlag?"yes":"no")); + } + } + } +#endif + break; + } +} + +void dump_mpeg2_ts(char *mpeg2ts_file, char *out_name, Bool prog_num) +{ + char data[188]; + GF_M2TS_Dump dumper; + + u32 size; + u64 fsize, fdone; + GF_M2TS_Demuxer *ts; + FILE *src; + + src = gf_fopen(mpeg2ts_file, "rb"); + if (!src) { + fprintf(stderr, "Cannot open %s: no such file\n", mpeg2ts_file); + return; + } + ts = gf_m2ts_demux_new(); + ts->on_event = on_m2ts_dump_event; + ts->notify_pes_timing = 1; + memset(&dumper, 0, sizeof(GF_M2TS_Dump)); + ts->user = &dumper; + dumper.prog_number = prog_num; + + /*PES dumping*/ + if (out_name) { + char *pid = strrchr(out_name, '#'); + if (pid) { + dumper.dump_pid = atoi(pid+1); + pid[0] = 0; + sprintf(dumper.dump, "%s_%d.raw", out_name, dumper.dump_pid); + dumper.pes_out = gf_fopen(dumper.dump, "wb"); +#if 0 + sprintf(dumper.nhml, "%s_%d.nhml", pes_out_name, dumper.dump_pid); + dumper.pes_out_nhml = gf_fopen(dumper.nhml, "wt"); + sprintf(dumper.info, "%s_%d.info", pes_out_name, dumper.dump_pid); + dumper.pes_out_info = gf_fopen(dumper.info, "wb"); +#endif + pid[0] = '#'; + } + } + + + gf_fseek(src, 0, SEEK_END); + fsize = gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); + fdone = 0; + + /* first loop to process all packets between two PAT, and assume all signaling was found between these 2 PATs */ + while (!feof(src)) { + size = (u32) fread(data, 1, 188, src); + if (size<188) break; + + gf_m2ts_process_data(ts, data, size); + if (dumper.has_seen_pat) break; + } + dumper.has_seen_pat = 1; + + if (prog_num) { + sprintf(dumper.timestamps_info_name, "%s_prog_%d_timestamps.txt", mpeg2ts_file, prog_num/*, mpeg2ts_file*/); + dumper.timestamps_info_file = gf_fopen(dumper.timestamps_info_name, "wt"); + if (!dumper.timestamps_info_file) { + fprintf(stderr, "Cannot open file %s\n", dumper.timestamps_info_name); + return; + } + fprintf(dumper.timestamps_info_file, "PCK#\tPID\tPCR\tDTS\tPTS\tRAP\tDiscontinuity\tDTS-PCR Diff\n"); + } + + gf_m2ts_reset_parsers(ts); + gf_fseek(src, 0, SEEK_SET); + fdone = 0; + + + while (!feof(src)) { + size = (u32) fread(data, 1, 188, src); + if (size<188) break; + + gf_m2ts_process_data(ts, data, size); + + fdone += size; + gf_set_progress("MPEG-2 TS Parsing", fdone, fsize); + } + + + gf_fclose(src); + gf_m2ts_demux_del(ts); + if (dumper.pes_out) gf_fclose(dumper.pes_out); +#if 0 + if (dumper.pes_out_nhml) { + if (dumper.is_info_dumped) fprintf(dumper.pes_out_nhml, "\n"); + gf_fclose(dumper.pes_out_nhml); + gf_fclose(dumper.pes_out_info); + } +#endif + if (dumper.timestamps_info_file) gf_fclose(dumper.timestamps_info_file); + +} + + +#endif /*GPAC_DISABLE_MPEG2TS*/ + + diff --git a/applications/mp4box/fileimport.c b/applications/mp4box/fileimport.c new file mode 100644 index 0000000..80bfb8f --- /dev/null +++ b/applications/mp4box/fileimport.c @@ -0,0 +1,2782 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2000-2012 + * All rights reserved + * + * This file is part of GPAC / mp4box application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include +#include +#include +#include + +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_SVG) +#include +#endif + + +#ifndef GPAC_DISABLE_BIFS +#include +#endif +#ifndef GPAC_DISABLE_VRML +#include +#endif + +#ifndef GPAC_DISABLE_ISOM_WRITE + +#include + +typedef struct +{ + const char *root_file; + const char *dir; + GF_List *imports; +} WGTEnum; + +#ifndef GPAC_DISABLE_MEDIA_IMPORT + +extern u32 swf_flags; +extern Float swf_flatten_angle; +extern Bool keep_sys_tracks; + +void scene_coding_log(void *cbk, u32 log_level, u32 log_tool, const char *fmt, va_list vlist); + +void convert_file_info(char *inName, u32 trackID) +{ + GF_Err e; + u32 i; + Bool found; + GF_MediaImporter import; + memset(&import, 0, sizeof(GF_MediaImporter)); + import.trackID = trackID; + import.in_name = inName; + import.flags = GF_IMPORT_PROBE_ONLY; + e = gf_media_import(&import); + if (e) { + fprintf(stderr, "Error probing file %s: %s\n", inName, gf_error_to_string(e)); + return; + } + if (trackID) { + fprintf(stderr, "Import probing results for track %s#%d:\n", inName, trackID); + } else { + fprintf(stderr, "Import probing results for %s:\n", inName); + if (!import.nb_tracks) { + fprintf(stderr, "File has no selectable tracks\n"); + return; + } + fprintf(stderr, "File has %d tracks\n", import.nb_tracks); + } + if (import.probe_duration) { + fprintf(stderr, "Duration: %g s\n", (Double) (import.probe_duration/1000.0)); + } + found = 0; + for (i=0; i> 16, import.tk_info[i].video_info.par & 0xFFFF); + fprintf(stderr, "\n"); + } + else if ((import.tk_info[i].type==GF_ISOM_MEDIA_AUDIO) && import.tk_info[i].audio_info.sample_rate) { + fprintf(stderr, "Source: %s - SampleRate %d - %d channels\n", gf_4cc_to_str(import.tk_info[i].media_type), import.tk_info[i].audio_info.sample_rate, import.tk_info[i].audio_info.nb_channels); + } else { + fprintf(stderr, "Source: %s\n", gf_4cc_to_str(import.tk_info[i].media_type)); + } + + + fprintf(stderr, "\nImport Capabilities:\n"); + if (import.tk_info[i].flags & GF_IMPORT_USE_DATAREF) fprintf(stderr, "\tCan use data referencing\n"); + if (import.tk_info[i].flags & GF_IMPORT_NO_FRAME_DROP) fprintf(stderr, "\tCan use fixed FPS import\n"); + if (import.tk_info[i].flags & GF_IMPORT_FORCE_PACKED) fprintf(stderr, "\tCan force packed bitstream import\n"); + if (import.tk_info[i].flags & GF_IMPORT_OVERRIDE_FPS) fprintf(stderr, "\tCan override source frame rate\n"); + if (import.tk_info[i].flags & (GF_IMPORT_SBR_IMPLICIT|GF_IMPORT_SBR_EXPLICIT)) fprintf(stderr, "\tCan use AAC-SBR signaling\n"); + if (import.tk_info[i].flags & (GF_IMPORT_PS_IMPLICIT|GF_IMPORT_PS_EXPLICIT)) fprintf(stderr, "\tCan use AAC-PS signaling\n"); + if (import.tk_info[i].flags & GF_IMPORT_FORCE_MPEG4) fprintf(stderr, "\tCan force MPEG-4 Systems signaling\n"); + if (import.tk_info[i].flags & GF_IMPORT_3GPP_AGGREGATION) fprintf(stderr, "\tCan use 3GPP frame aggregation\n"); + if (import.tk_info[i].flags & GF_IMPORT_NO_DURATION) fprintf(stderr, "\tCannot use duration-based import\n"); + + found = 1; + break; + } + fprintf(stderr, "\n"); + if (!found && trackID) fprintf(stderr, "Cannot find track %d in file\n", trackID); +} + +static void set_chapter_track(GF_ISOFile *file, u32 track, u32 chapter_ref_trak) +{ + u64 ref_duration, chap_duration; + Double scale; + + gf_isom_set_track_reference(file, chapter_ref_trak, GF_4CC('c','h','a','p'), gf_isom_get_track_id(file, track) ); + gf_isom_set_track_enabled(file, track, 0); + + ref_duration = gf_isom_get_media_duration(file, chapter_ref_trak); + chap_duration = gf_isom_get_media_duration(file, track); + scale = (Double) (s64) gf_isom_get_media_timescale(file, track); + scale /= gf_isom_get_media_timescale(file, chapter_ref_trak); + ref_duration = (u64) (ref_duration * scale); + + if (chap_duration < ref_duration) { + chap_duration -= gf_isom_get_sample_duration(file, track, gf_isom_get_sample_count(file, track)); + chap_duration = ref_duration - chap_duration; + gf_isom_set_last_sample_duration(file, track, (u32) chap_duration); + } +} + +GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, Bool is_box_array) +{ + char *data = NULL; + u32 size; + bin128 uuid; + memset(uuid, 0 , 16); + + if (!udta_type && !is_box_array) return GF_BAD_PARAM; + + if (!src) { + return gf_isom_remove_user_data(dest, tracknum, udta_type, uuid); + } + + if (!strnicmp(src, "base64", 6)) { + src += 7; + size = (u32) strlen(src); + data = gf_malloc(sizeof(char) * size); + size = gf_base64_decode(src, size, data, size); + } else { + FILE *t = gf_fopen(src, "rb"); + if (!t) return GF_IO_ERR; + fseek(t, 0, SEEK_END); + size = ftell(t); + fseek(t, 0, SEEK_SET); + data = gf_malloc(sizeof(char)*size); + if (size != fread(data, 1, size, t) ) { + gf_free(data); + gf_fclose(t); + return GF_IO_ERR; + } + gf_fclose(t); + } + + if (size && data) { + if (is_box_array) { + gf_isom_add_user_data_boxes(dest, tracknum, data, size); + } else { + gf_isom_add_user_data(dest, tracknum, udta_type, uuid, data, size); + } + gf_free(data); + } + return GF_OK; +} + +GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample) +{ + u32 track_id, i, j, timescale, track, stype, profile, level, new_timescale, rescale, svc_mode, tile_mode, txt_flags; + s32 par_d, par_n, prog_id, delay; + s32 tw, th, tx, ty, txtw, txth, txtx, txty; + Bool do_audio, do_video, do_all, disable, track_layout, text_layout, chap_ref, is_chap, is_chap_file, keep_handler, negative_cts_offset, rap_only; + u32 group, handler, rvc_predefined, check_track_for_svc, check_track_for_shvc; + const char *szLan; + GF_Err e; + GF_MediaImporter import; + char *ext, szName[1000], *handler_name, *rvc_config, *chapter_name; + GF_List *kinds; + GF_TextFlagsMode txt_mode = GF_ISOM_TEXT_FLAGS_OVERWRITE; + + rvc_predefined = 0; + chapter_name = NULL; + new_timescale = 1; + rescale = 0; + text_layout = 0; + /*0: merge all + 1: split base and all SVC in two tracks + 2: split all base and SVC layers in dedicated tracks + */ + svc_mode = 0; + + memset(&import, 0, sizeof(GF_MediaImporter)); + + strcpy(szName, inName); + + is_chap_file = 0; + handler = 0; + disable = 0; + chap_ref = 0; + is_chap = 0; + kinds = gf_list_new(); + track_layout = 0; + szLan = NULL; + delay = 0; + group = 0; + stype = 0; + profile = level = 0; + negative_cts_offset = 0; + tile_mode = 0; + rap_only = 0; + txt_flags = 0; + + tw = th = tx = ty = txtw = txth = txtx = txty = 0; + par_d = par_n = -2; + /*use ':' as separator, but beware DOS paths...*/ + ext = strchr(szName, ':'); + if (ext && ext[1]=='\\') ext = strchr(szName+2, ':'); + + handler_name = NULL; + rvc_config = NULL; + while (ext) { + char *ext2 = strchr(ext+1, ':'); + if (ext2 && !strncmp(ext2, "://", 3)) ext2 = strchr(ext2+1, ':'); + if (ext2 && !strncmp(ext2, ":\\", 2)) ext2 = strchr(ext2+1, ':'); + if (ext2) ext2[0] = 0; + + /*all extensions for track-based importing*/ + if (!strnicmp(ext+1, "dur=", 4)) import.duration = (u32) (atof(ext+5) * 1000); + else if (!strnicmp(ext+1, "lang=", 5)) szLan = ext+6; + else if (!strnicmp(ext+1, "delay=", 6)) delay = atoi(ext+7); + else if (!strnicmp(ext+1, "par=", 4)) { + if (!stricmp(ext+5, "none")) { + par_n = par_d = -1; + } else { + if (ext2) ext2[0] = ':'; + if (ext2) ext2 = strchr(ext2+1, ':'); + if (ext2) ext2[0] = 0; + sscanf(ext+5, "%d:%d", &par_n, &par_d); + } + } + else if (!strnicmp(ext+1, "name=", 5)) handler_name = gf_strdup(ext+6); + else if (!strnicmp(ext+1, "ext=", 4)) { + /*extensions begin with '.'*/ + if (*(ext+5) == '.') + import.force_ext = gf_strdup(ext+5); + else { + import.force_ext = gf_calloc(1+strlen(ext+5)+1, 1); + import.force_ext[0] = '.'; + strcat(import.force_ext+1, ext+5); + } + } + else if (!strnicmp(ext+1, "hdlr=", 5)) handler = GF_4CC(ext[6], ext[7], ext[8], ext[9]); + else if (!strnicmp(ext+1, "disable", 7)) disable = 1; + else if (!strnicmp(ext+1, "group=", 6)) { + group = atoi(ext+7); + if (!group) group = gf_isom_get_next_alternate_group_id(dest); + } + else if (!strnicmp(ext+1, "fps=", 4)) { + if (!strcmp(ext+5, "auto")) force_fps = GF_IMPORT_AUTO_FPS; + else if (strchr(ext+5, '-')) { + u32 ticks, dts_inc; + sscanf(ext+5, "%u-%u", &ticks, &dts_inc); + if (!dts_inc) dts_inc=1; + force_fps = ticks; + force_fps /= dts_inc; + } + else force_fps = atof(ext+5); + } + else if (!stricmp(ext+1, "rap")) rap_only = 1; + else if (!stricmp(ext+1, "trailing")) import_flags |= GF_IMPORT_KEEP_TRAILING; + else if (!strnicmp(ext+1, "agg=", 4)) frames_per_sample = atoi(ext+5); + else if (!stricmp(ext+1, "dref")) import_flags |= GF_IMPORT_USE_DATAREF; + else if (!stricmp(ext+1, "nodrop")) import_flags |= GF_IMPORT_NO_FRAME_DROP; + else if (!stricmp(ext+1, "packed")) import_flags |= GF_IMPORT_FORCE_PACKED; + else if (!stricmp(ext+1, "sbr")) import_flags |= GF_IMPORT_SBR_IMPLICIT; + else if (!stricmp(ext+1, "sbrx")) import_flags |= GF_IMPORT_SBR_EXPLICIT; + else if (!stricmp(ext+1, "ovsbr")) import_flags |= GF_IMPORT_OVSBR; + else if (!stricmp(ext+1, "ps")) import_flags |= GF_IMPORT_PS_IMPLICIT; + else if (!stricmp(ext+1, "psx")) import_flags |= GF_IMPORT_PS_EXPLICIT; + else if (!stricmp(ext+1, "mpeg4")) import_flags |= GF_IMPORT_FORCE_MPEG4; + else if (!stricmp(ext+1, "svc") || !stricmp(ext+1, "shvc") ) import_flags |= GF_IMPORT_SVC_EXPLICIT; + else if (!stricmp(ext+1, "nosvc") || !stricmp(ext+1, "noshvc")) import_flags |= GF_IMPORT_SVC_NONE; + /*split SVC layers*/ + else if (!strnicmp(ext+1, "svcmode=", 8) || !strnicmp(ext+1, "shvcmode=", 9)) { + char *mode = ext+9; + if (mode[0]=='=') mode = ext+10; + + if (!stricmp(mode, "splitnox")) + svc_mode = 3; + else if (!stricmp(mode, "splitall") || !stricmp(mode, "split")) + svc_mode = 2; + else if (!stricmp(mode, "splitbase")) + svc_mode = 1; + else if (!stricmp(mode, "merged")) + svc_mode = 0; + } + else if (!stricmp(ext+1, "subsamples")) import_flags |= GF_IMPORT_SET_SUBSAMPLES; + else if (!stricmp(ext+1, "forcesync")) import_flags |= GF_IMPORT_FORCE_SYNC; + else if (!stricmp(ext+1, "xps_inband")) import_flags |= GF_IMPORT_FORCE_XPS_INBAND; + + /*force all composition offsets to be positive*/ + else if (!strnicmp(ext+1, "negctts", 7)) negative_cts_offset = 1; + else if (!strnicmp(ext+1, "stype=", 6)) { + stype = GF_4CC(ext[7], ext[8], ext[9], ext[10]); + } + else if (!stricmp(ext+1, "chap")) is_chap = 1; + else if (!strnicmp(ext+1, "chapter=", 8)) chapter_name = gf_strdup(ext+9); + else if (!strnicmp(ext+1, "chapfile=", 9)) { + chapter_name = gf_strdup(ext+10); + is_chap_file=1; + } + else if (!strnicmp(ext+1, "layout=", 7)) { + if ( sscanf(ext+8, "%dx%dx%dx%d", &tw, &th, &tx, &ty)==4) { + track_layout = 1; + } else if ( sscanf(ext+8, "%dx%d", &tw, &th)==2) { + track_layout = 1; + tx = ty = 0; + } + } + else if (!strnicmp(ext+1, "rescale=", 8)) { + rescale = atoi(ext+9); + } + else if (!strnicmp(ext+1, "timescale=", 10)) { + new_timescale = atoi(ext+11); + } + else if (!stricmp(ext+1, "noedit")) import_flags |= GF_IMPORT_NO_EDIT_LIST; + + + else if (!strnicmp(ext+1, "rvc=", 4)) { + if (sscanf(ext+5, "%d", &rvc_predefined) != 1) { + rvc_config = gf_strdup(ext+5); + } + } + else if (!strnicmp(ext+1, "fmt=", 4)) import.streamFormat = gf_strdup(ext+5); + else if (!strnicmp(ext+1, "profile=", 8)) profile = atoi(ext+9); + else if (!strnicmp(ext+1, "level=", 6)) level = atoi(ext+7); + + else if (!strnicmp(ext+1, "font=", 5)) import.fontName = gf_strdup(ext+6); + else if (!strnicmp(ext+1, "size=", 5)) import.fontSize = atoi(ext+6); + else if (!strnicmp(ext+1, "text_layout=", 12)) { + if ( sscanf(ext+13, "%dx%dx%dx%d", &txtw, &txth, &txtx, &txty)==4) { + text_layout = 1; + } else if ( sscanf(ext+8, "%dx%d", &txtw, &txth)==2) { + track_layout = 1; + txtx = txty = 0; + } + } + + else if (!stricmp(ext+1, "swf-global")) import.swf_flags |= GF_SM_SWF_STATIC_DICT; + else if (!stricmp(ext+1, "swf-no-ctrl")) import.swf_flags &= ~GF_SM_SWF_SPLIT_TIMELINE; + else if (!stricmp(ext+1, "swf-no-text")) import.swf_flags |= GF_SM_SWF_NO_TEXT; + else if (!stricmp(ext+1, "swf-no-font")) import.swf_flags |= GF_SM_SWF_NO_FONT; + else if (!stricmp(ext+1, "swf-no-line")) import.swf_flags |= GF_SM_SWF_NO_LINE; + else if (!stricmp(ext+1, "swf-no-grad")) import.swf_flags |= GF_SM_SWF_NO_GRADIENT; + else if (!stricmp(ext+1, "swf-quad")) import.swf_flags |= GF_SM_SWF_QUAD_CURVE; + else if (!stricmp(ext+1, "swf-xlp")) import.swf_flags |= GF_SM_SWF_SCALABLE_LINE; + else if (!stricmp(ext+1, "swf-ic2d")) import.swf_flags |= GF_SM_SWF_USE_IC2D; + else if (!stricmp(ext+1, "swf-same-app")) import.swf_flags |= GF_SM_SWF_REUSE_APPEARANCE; + else if (!strnicmp(ext+1, "swf-flatten=", 12)) import.swf_flatten_angle = (Float) atof(ext+13); + + else if (!strnicmp(ext+1, "kind=", 5)) { + char *kind_scheme, *kind_value; + char *kind_data = ext+6; + char *sep = strchr(kind_data, '='); + if (sep) { + *sep = 0; + } + kind_scheme = gf_strdup(kind_data); + if (sep) { + *sep = '='; + kind_value = gf_strdup(sep+1); + } else { + kind_value = NULL; + } + gf_list_add(kinds, kind_scheme); + gf_list_add(kinds, kind_value); + } + else if (!strnicmp(ext+1, "txtflags", 8)) { + if (!strnicmp(ext+1, "txtflags=", 9)) { + sscanf(ext+10, "%x", &txt_flags); + } + else if (!strnicmp(ext+1, "txtflags+=", 10)) { + sscanf(ext+11, "%x", &txt_flags); + txt_mode = GF_ISOM_TEXT_FLAGS_TOGGLE; + } + else if (!strnicmp(ext+1, "txtflags-=", 10)) { + sscanf(ext+11, "%x", &txt_flags); + txt_mode = GF_ISOM_TEXT_FLAGS_UNTOGGLE; + } + } + + /*EXPERIMENTAL OPTIONS NOT DOCUMENTED*/ + else if (!strnicmp(ext+1, "tiles", 5)) { + tile_mode = 1; + } + + /*unrecognized, assume name has colon in it*/ + else { + ext = ext2; + continue; + } + + if (ext2) ext2[0] = ':'; + ext2 = ext+1; + ext[0] = 0; + ext = strchr(ext+1, ':'); + } + + /*check duration import (old syntax)*/ + ext = strrchr(szName, '%'); + if (ext) { + import.duration = (u32) (atof(ext+1) * 1000); + ext[0] = 0; + } + + /*select switches for av containers import*/ + do_audio = do_video = 0; + track_id = prog_id = 0; + do_all = 1; + ext = strrchr(szName, '#'); + if (ext) ext[0] = 0; + + keep_handler = gf_isom_probe_file(szName); + + import.in_name = szName; + import.flags = GF_IMPORT_PROBE_ONLY; + e = gf_media_import(&import); + if (e) goto exit; + + if (ext) { + ext++; + if (!strnicmp(ext, "audio", 5)) do_audio = 1; + else if (!strnicmp(ext, "video", 5)) do_video = 1; + else if (!strnicmp(ext, "trackID=", 8)) track_id = atoi(&ext[8]); + else if (!strnicmp(ext, "PID=", 4)) track_id = atoi(&ext[4]); + else if (!strnicmp(ext, "program=", 8)) { + for (i=0; i=0) && (par_d>=0)) { + e = gf_media_change_par(import.dest, i+1, par_n, par_d); + } + + if (rap_only) { + e = gf_media_remove_non_rap(import.dest, i+1); + } + + if (handler_name) gf_isom_set_handler_name(import.dest, i+1, handler_name); + else if (!keep_handler) { + char szHName[1024]; + const char *fName = gf_url_get_resource_name((const char *)inName); + fName = strchr(fName, '.'); + if (fName) fName += 1; + else fName = "?"; + + sprintf(szHName, "*%s@GPAC%s", fName, GPAC_FULL_VERSION); + gf_isom_set_handler_name(import.dest, i+1, szHName); + } + if (handler) gf_isom_set_media_type(import.dest, i+1, handler); + if (disable) gf_isom_set_track_enabled(import.dest, i+1, 0); + + if (group) { + gf_isom_set_alternate_group_id(import.dest, i+1, group); + } + if (track_layout) { + gf_isom_set_track_layout_info(import.dest, i+1, tw<<16, th<<16, tx<<16, ty<<16, 0); + } + if (stype) + gf_isom_set_media_subtype(import.dest, i+1, 1, stype); + + if (is_chap && chap_ref) { + set_chapter_track(import.dest, i+1, chap_ref); + } + + for (j = 0; j < gf_list_count(kinds); j+=2) { + char *kind_scheme = (char *)gf_list_get(kinds, j); + char *kind_value = (char *)gf_list_get(kinds, j+1); + gf_isom_add_track_kind(import.dest, i+1, kind_scheme, kind_value); + } + + if (profile || level) + gf_media_change_pl(import.dest, i+1, profile, level); + + if (gf_isom_get_media_subtype(import.dest, i+1, 1)== GF_4CC( 'm', 'p', '4', 's' )) + keep_sys_tracks = 1; + + gf_isom_set_composition_offset_mode(import.dest, i+1, negative_cts_offset); + + if (gf_isom_get_avc_svc_type(import.dest, i+1, 1)>=GF_ISOM_AVCTYPE_AVC_SVC) + check_track_for_svc = i+1; + + if (gf_isom_get_hevc_shvc_type(import.dest, i+1, 1)>=GF_ISOM_HEVCTYPE_HEVC_SHVC) + check_track_for_shvc = i+1; + + if (txt_flags) { + gf_isom_text_set_display_flags(import.dest, i+1, 0, txt_flags, txt_mode); + } + + + if (tile_mode) { + switch (gf_isom_get_media_subtype(import.dest, i+1, 1)) { + case GF_ISOM_SUBTYPE_HVC1: + case GF_ISOM_SUBTYPE_HEV1: + tile_mode = 2; + break; + } + } + } + } else { + for (i=0; i0) { + gf_isom_append_edit_segment(import.dest, track, (timescale*delay)/1000, 0, GF_ISOM_EDIT_EMPTY); + gf_isom_append_edit_segment(import.dest, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL); + } else { + u64 to_skip = (timescale*(-delay))/1000; + if (to_skip=-1) && (par_d>=-1)) { + e = gf_media_change_par(import.dest, track, par_n, par_d); + } + if (rap_only) { + e = gf_media_remove_non_rap(import.dest, track); + } + if (handler_name) gf_isom_set_handler_name(import.dest, track, handler_name); + else if (!keep_handler) { + char szHName[1024]; + const char *fName = gf_url_get_resource_name((const char *)inName); + fName = strchr(fName, '.'); + if (fName) fName += 1; + else fName = "?"; + + sprintf(szHName, "%s@GPAC%s", fName, GPAC_FULL_VERSION); + gf_isom_set_handler_name(import.dest, track, szHName); + } + if (handler) gf_isom_set_media_type(import.dest, track, handler); + + if (group) { + gf_isom_set_alternate_group_id(import.dest, track, group); + } + + if (track_layout) { + gf_isom_set_track_layout_info(import.dest, track, tw<<16, th<<16, tx<<16, ty<<16, 0); + } + if (stype) + gf_isom_set_media_subtype(import.dest, track, 1, stype); + + if (is_chap && chap_ref) { + set_chapter_track(import.dest, track, chap_ref); + } + + for (j = 0; j < gf_list_count(kinds); j+=2) { + char *kind_scheme = (char *)gf_list_get(kinds, j); + char *kind_value = (char *)gf_list_get(kinds, j+1); + gf_isom_add_track_kind(import.dest, i+1, kind_scheme, kind_value); + } + + if (profile || level) + gf_media_change_pl(import.dest, track, profile, level); + + if (gf_isom_get_mpeg4_subtype(import.dest, track, 1)) + keep_sys_tracks = 1; + + if (new_timescale>1) { + gf_isom_set_media_timescale(import.dest, track, new_timescale, 0); + } + if (rescale>1) { + switch (gf_isom_get_media_type(import.dest, track)) { + case GF_ISOM_MEDIA_AUDIO: + fprintf(stderr, "Cannot force media timescale for audio media types - ignoring\n"); + break; + default: + gf_isom_set_media_timescale(import.dest, track, rescale, 1); + break; + } + } + + if (rvc_config) { + FILE *f = gf_fopen(rvc_config, "rb"); + if (f) { + char *data; + u32 size; + size_t read; + gf_fseek(f, 0, SEEK_END); + size = (u32) gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); + data = gf_malloc(sizeof(char)*size); + read = fread(data, 1, size, f); + assert(read); + assert(read == size); + gf_fclose(f); +#ifdef GPAC_DISABLE_ZLIB + fprintf(stderr, "Error: no zlib support - RVC not available\n"); + e = GF_NOT_SUPPORTED; + goto exit; +#endif + gf_gz_compress_payload(&data, size, &size); + gf_isom_set_rvc_config(import.dest, track, 1, 0, "application/rvc-config+xml+gz", data, size); + gf_free(data); + } + } else if (rvc_predefined>0) { + gf_isom_set_rvc_config(import.dest, track, 1, rvc_predefined, NULL, NULL, 0); + } + + gf_isom_set_composition_offset_mode(import.dest, track, negative_cts_offset); + + if (gf_isom_get_avc_svc_type(import.dest, track, 1)>=GF_ISOM_AVCTYPE_AVC_SVC) + check_track_for_svc = track; + + if (gf_isom_get_hevc_shvc_type(import.dest, track, 1)>=GF_ISOM_HEVCTYPE_HEVC_SHVC) + check_track_for_shvc = track; + + if (txt_flags) { + gf_isom_text_set_display_flags(import.dest, track, 0, txt_flags, txt_mode); + } + + if (tile_mode) { + switch (gf_isom_get_media_subtype(import.dest, track, 1)) { + case GF_ISOM_SUBTYPE_HVC1: + case GF_ISOM_SUBTYPE_HEV1: + tile_mode = 2; + break; + } + } + } + if (track_id) fprintf(stderr, "WARNING: Track ID %d not found in file\n", track_id); + else if (do_video) fprintf(stderr, "WARNING: Video track not found\n"); + else if (do_audio) fprintf(stderr, "WARNING: Audio track not found\n"); + } + + if (chapter_name) { + if (is_chap_file) { + e = gf_media_import_chapters(import.dest, chapter_name, 0); + } else { + e = gf_isom_add_chapter(import.dest, 0, 0, chapter_name); + } + } + + /*force to rewrite all dependencies*/ + for (i = 1; i <= gf_isom_get_track_count(import.dest); i++) + { + e = gf_isom_rewrite_track_dependencies(import.dest, i); + if (e) { + fprintf(stderr, "Warning: track ID %d has references to a track not imported\n", gf_isom_get_track_id(import.dest, i)); + e = GF_OK; + } + } + + if (check_track_for_svc) { + if (svc_mode) { + e = gf_media_split_svc(import.dest, check_track_for_svc, (svc_mode==2) ? 1 : 0); + if (e) goto exit; + } else { + e = gf_media_merge_svc(import.dest, check_track_for_svc, 1); + if (e) goto exit; + } + } + if (check_track_for_shvc) { + if (svc_mode) { + e = gf_media_split_shvc(import.dest, check_track_for_shvc, (svc_mode==1) ? 0 : 1, (svc_mode==3) ? 0 : 1 ); + if (e) goto exit; + } else { + //TODO - merge + } + } + if (tile_mode == 2) { + gf_media_split_hevc_tiles(import.dest); + } + + +exit: + while (gf_list_count(kinds)) { + char *kind = (char *)gf_list_get(kinds, 0); + gf_list_rem(kinds, 0); + if (kind) gf_free(kind); + } + gf_list_del(kinds); + if (handler_name) gf_free(handler_name); + if (chapter_name ) gf_free(chapter_name ); + if (import.fontName) gf_free(import.fontName); + if (import.streamFormat) gf_free(import.streamFormat); + if (import.force_ext) gf_free(import.force_ext); + if (rvc_config) gf_free(rvc_config); + return e; +} + +typedef struct +{ + u32 tk; + Bool has_non_raps; + u32 last_sample; + u32 sample_count; + u32 time_scale; + u64 firstDTS, lastDTS; + u32 dst_tk; + /*set if media can be duplicated at split boundaries - only used for text tracks and provate tracks, this assumes all + samples are RAP*/ + Bool can_duplicate; + /*controls import by time rather than by sample (otherwise we would have to remove much more samples video vs audio for example*/ + Bool first_sample_done; + Bool next_sample_is_rap; + u32 stop_state; +} TKInfo; + +GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, char *inName, Double InterleavingTime, Double chunk_start_time, Bool adjust_split_end, char *outName, const char *tmpdir) +{ + u32 i, count, nb_tk, needs_rap_sync, cur_file, conv_type, nb_tk_done, nb_samp, nb_done, di; + Double max_dur, cur_file_time; + Bool do_add, all_duplicatable, size_exceeded, chunk_extraction, rap_split, split_until_end; + GF_ISOFile *dest; + GF_ISOSample *samp; + GF_Err e; + TKInfo *tks, *tki; + char *ext, szName[1000], szFile[1000]; + Double chunk_start = (Double) chunk_start_time; + + chunk_extraction = (chunk_start>=0) ? 1 : 0; + split_until_end = 0; + rap_split = 0; + if (split_size_kb==(u32) -1) rap_split = 1; + if (split_dur==-1) rap_split = 1; + else if (split_dur==-2) { + split_size_kb = 0; + split_until_end = 1; + split_dur = 0; + } + + if (rap_split) { + split_size_kb = 0; + split_dur = (double) GF_MAX_FLOAT; + } + + + ext = strrchr(inName, '/'); + if (!ext) ext = strrchr(inName, '\\'); + strcpy(szName, ext ? ext+1 : inName); + ext = strrchr(szName, '.'); + if (ext) ext[0] = 0; + ext = strrchr(inName, '.'); + + dest = NULL; + + conv_type = 0; + switch (gf_isom_guess_specification(mp4)) { + case GF_4CC('I','S','M','A'): + conv_type = 1; + break; + case GF_ISOM_BRAND_3GP4: + case GF_ISOM_BRAND_3GP5: + case GF_ISOM_BRAND_3GP6: + case GF_ISOM_BRAND_3GG6: + case GF_ISOM_BRAND_3G2A: + conv_type = 2; + break; + } + if (!stricmp(ext, ".3gp") || !stricmp(ext, ".3g2")) conv_type = 2; + + count = gf_isom_get_track_count(mp4); + tks = (TKInfo *)gf_malloc(sizeof(TKInfo)*count); + memset(tks, 0, sizeof(TKInfo)*count); + + e = GF_OK; + max_dur = 0; + nb_tk = 0; + all_duplicatable = 1; + needs_rap_sync = 0; + nb_samp = 0; + for (i=0; i1) { + break; + } + continue; + case GF_ISOM_MEDIA_HINT: + case GF_ISOM_MEDIA_SCENE: + case GF_ISOM_MEDIA_OCR: + case GF_ISOM_MEDIA_OD: + case GF_ISOM_MEDIA_OCI: + case GF_ISOM_MEDIA_IPMP: + case GF_ISOM_MEDIA_MPEGJ: + case GF_ISOM_MEDIA_MPEG7: + case GF_ISOM_MEDIA_FLASH: + fprintf(stderr, "WARNING: Track ID %d (type %s) not handled by splitter - skipping\n", gf_isom_get_track_id(mp4, i+1), gf_4cc_to_str(mtype)); + continue; + default: + /*for all other track types, only split if more than one sample*/ + if (gf_isom_get_sample_count(mp4, i+1)==1) { + fprintf(stderr, "WARNING: Track ID %d (type %s) not handled by splitter - skipping\n", gf_isom_get_track_id(mp4, i+1), gf_4cc_to_str(mtype)); + continue; + } + tks[nb_tk].can_duplicate = 1; + } + + tks[nb_tk].sample_count = gf_isom_get_sample_count(mp4, i+1); + nb_samp += tks[nb_tk].sample_count; + tks[nb_tk].last_sample = 0; + tks[nb_tk].firstDTS = 0; + tks[nb_tk].time_scale = gf_isom_get_media_timescale(mp4, i+1); + tks[nb_tk].has_non_raps = gf_isom_has_sync_points(mp4, i+1); + /*seen that on some 3gp files from nokia ...*/ + if (mtype==GF_ISOM_MEDIA_AUDIO) tks[nb_tk].has_non_raps = 0; + + dur = (Double) (s64) gf_isom_get_media_duration(mp4, i+1); + dur /= tks[nb_tk].time_scale; + if (max_dur=max_dur) { + fprintf(stderr, "Input file (%f) shorter than requested split start offset (%f)\n", max_dur, chunk_start); + gf_free(tks); + return GF_NOT_SUPPORTED; + } + if (split_until_end) { + split_dur = max_dur; + } else if (!rap_split && (max_dur<=split_dur)) { + fprintf(stderr, "Input file (%f) shorter than requested split duration (%f)\n", max_dur, split_dur); + gf_free(tks); + return GF_NOT_SUPPORTED; + } + if (needs_rap_sync) { + tki = &tks[needs_rap_sync-1]; + if ((gf_isom_get_sync_point_count(mp4, tki->tk)==1) && (chunk_start != 0.0f)) { + fprintf(stderr, "Not enough Random Access points in input file - cannot split\n"); + gf_free(tks); + return GF_NOT_SUPPORTED; + } + } + split_size_kb *= 1024; + cur_file_time = 0; + + if (chunk_start>0) { + if (needs_rap_sync) { + u32 sample_num; + Double start; + tki = &tks[needs_rap_sync-1]; + + start = (Double) (s64) gf_isom_get_sample_dts(mp4, tki->tk, tki->sample_count); + start /= tki->time_scale; + if (startstop_state = 2; + needs_rap_sync = 0; + } else { + e = gf_isom_get_sample_for_media_time(mp4, tki->tk, (u64) (chunk_start*tki->time_scale), &di, GF_ISOM_SEARCH_SYNC_BACKWARD, &samp, &sample_num); + if (e!=GF_OK) { + fprintf(stderr, "Cannot locate RAP in track ID %d for chunk extraction from %02.2f sec\n", gf_isom_get_track_id(mp4, tki->tk), chunk_start); + gf_free(tks); + return GF_NOT_SUPPORTED; + } + start = (Double) (s64) samp->DTS; + start /= tki->time_scale; + gf_isom_sample_del(&samp); + fprintf(stderr, "Adjusting chunk start time to previous random access at %02.2f sec\n", start); + split_dur += (chunk_start - start); + chunk_start = start; + } + } + /*sync all tracks*/ + for (i=0; ilast_samplesample_count) { + Double time; + u64 dts; + dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); + time = (Double) (s64) dts; + time /= tki->time_scale; + if (time>=chunk_start) { + /*rewind one sample (text tracks & co)*/ + if (tki->can_duplicate && tki->last_sample) { + tki->last_sample--; + tki->firstDTS = (u64) (chunk_start*tki->time_scale); + } else { + tki->firstDTS = dts; + } + break; + } + tki->last_sample++; + } + } + cur_file_time = chunk_start; + } else { + chunk_start = 0; + } + + dest = NULL; + nb_done = 0; + nb_tk_done = 0; + cur_file = 0; + while (nb_tk_donestop_state==2) continue; + + e = gf_isom_clone_track(mp4, tki->tk, dest, 0, &tki->dst_tk); + if (e) { + fprintf(stderr, "Error cloning track %d\n", tki->tk); + goto err_exit; + } + /*use non-packet CTS offsets (faster add/remove)*/ + if (gf_isom_has_time_offset(mp4, tki->tk)) { + gf_isom_set_cts_packing(dest, tki->dst_tk, 1); + } + gf_isom_remove_edit_segments(dest, tki->dst_tk); + } + do_add = 1; + is_last_rap = 0; + last_rap_sample_time = 0; + file_split_dur = split_dur; + + size_exceeded = 0; + max_dts = 0; + while (do_add) { + Double time; + u32 nb_over, nb_av = 0; + /*perfom basic de-interleaving to make sure we're not importing too much of a given track*/ + u32 nb_add = 0; + /*add one sample of each track*/ + for (i=0; ican_duplicate) nb_av++; + + if (tki->stop_state) + continue; + if (tki->last_sample==tki->sample_count) + continue; + + /*get sample info, see if we need to check it (basic de-interleaver)*/ + dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); + + /*reinsertion (timed text)*/ + if (dts < tki->firstDTS) { + samp = gf_isom_get_sample(mp4, tki->tk, tki->last_sample+1, &di); + samp->DTS = 0; + e = gf_isom_add_sample(dest, tki->dst_tk, di, samp); + gf_isom_sample_del(&samp); + tki->last_sample += 1; + dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); + } + dts -= tki->firstDTS; + + + t = (Double) (s64) dts; + t /= tki->time_scale; + if (tki->first_sample_done) { + if (!all_av_done && (t>max_dts)) continue; + } else { + /*here's the trick: only take care of a/v media for splitting, and add other media + only if thir dts is less than the max AV dts found. Otherwise with some text streams we will end up importing + too much video and corrupting the last sync point indication*/ + if (!tki->can_duplicate && (t>max_dts)) max_dts = t; + tki->first_sample_done = 1; + } + samp = gf_isom_get_sample(mp4, tki->tk, tki->last_sample+1, &di); + samp->DTS -= tki->firstDTS; + + nb_add += 1; + + if (tki->has_non_raps && samp->IsRAP) { + GF_ISOSample *next_rap; + u32 next_rap_num, sdi; + last_rap_sample_time = (Double) (s64) samp->DTS; + last_rap_sample_time /= tki->time_scale; + e = gf_isom_get_sample_for_media_time(mp4, tki->tk, samp->DTS+tki->firstDTS+2, &sdi, GF_ISOM_SEARCH_SYNC_FORWARD, &next_rap, &next_rap_num); + if (e==GF_EOS) + is_last_rap = 1; + if (next_rap) { + if (!next_rap->IsRAP) + is_last_rap = 1; + gf_isom_sample_del(&next_rap); + } + } + tki->lastDTS = samp->DTS; + e = gf_isom_add_sample(dest, tki->dst_tk, di, samp); + gf_isom_sample_del(&samp); + tki->last_sample += 1; + gf_set_progress("Splitting", nb_done, nb_samp); + nb_done++; + if (e) { + fprintf(stderr, "Error cloning track %d sample %d\n", tki->tk, tki->last_sample); + goto err_exit; + } + + tki->next_sample_is_rap = 0; + if (rap_split && tki->has_non_raps) { + if ( gf_isom_get_sample_sync(mp4, tki->tk, tki->last_sample+1)) + tki->next_sample_is_rap = 1; + } + } + + /*test by size/duration*/ + nb_over = 0; + + /*test by file size: same as duration test, only dynamically increment import duration*/ + if (split_size_kb) { + u64 est_size = gf_isom_estimate_size(dest); + /*while below desired size keep importing*/ + if (est_sizestop_state) { + nb_over++; + if (!tki->can_duplicate && (tki->last_sample==tki->sample_count) ) + nb_av--; + continue; + } + time = (Double) (s64) tki->lastDTS; + time /= tki->time_scale; + if (size_exceeded + || (tki->last_sample==tki->sample_count) + || (!tki->can_duplicate && (time>file_split_dur)) + || (rap_split && tki->has_non_raps && tki->next_sample_is_rap) + ) { + nb_over++; + tki->stop_state = 1; + if (tki->last_samplesample_count) + is_last_rap = 0; + else if (tki->first_sample_done) + is_last_rap = 0; + + if (rap_split && tki->next_sample_is_rap) { + file_split_dur = (Double) ( gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1) - tki->firstDTS); + file_split_dur /= tki->time_scale; + } + } + /*special tracks (not audio, not video)*/ + else if (tki->can_duplicate) { + u64 dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); + time = (Double) (s64) (dts - tki->firstDTS); + time /= tki->time_scale; + if (time>file_split_dur) { + nb_over++; + tki->stop_state = 1; + } + } + if (!nb_add && (!max_dts || (tki->lastDTS <= 1 + (u64) (tki->time_scale*max_dts) ))) + tki->first_sample_done = 0; + } + if (nb_over==nb_tk) do_add = 0; + + if (!nb_av) + all_av_done = GF_TRUE; + } + + /*remove samples - first figure out smallest duration*/ + file_split_dur = (Double) GF_MAX_FLOAT; + for (i=0; istop_state==2) || (!is_last_rap && (tki->sample_count == tki->last_sample)) ) { + if (tki->has_non_raps) last_rap_sample_time = 0; + time = (Double) (s64) ( gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1) - tki->firstDTS); + time /= tki->time_scale; + if (file_split_dur==(Double)GF_MAX_FLOAT || file_split_durlastDTS) + { + //time = (Double) (s64) tki->lastDTS; + time = (Double) (s64) ( gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1) - tki->firstDTS); + time /= tki->time_scale; + if ((!tki->can_duplicate || all_duplicatable) && timenext_sample_is_rap) file_split_dur = time; + } + } + if (file_split_dur == (Double) GF_MAX_FLOAT) { + fprintf(stderr, "Cannot split file (duration too small or size too small)\n"); + goto err_exit; + } + if (chunk_extraction) { + if (adjust_split_end) { + fprintf(stderr, "Adjusting chunk end time to previous random access at %02.2f sec\n", chunk_start + last_rap_sample_time); + file_split_dur = last_rap_sample_time; + if (outName) strcpy(szFile, outName); + else sprintf(szFile, "%s_%d_%d%s", szName, (u32) chunk_start, (u32) (chunk_start+file_split_dur), ext); + gf_isom_set_final_name(dest, szFile); + } + else file_split_dur = split_dur; + } + + /*don't split if eq to copy...*/ + if (is_last_rap && !cur_file && !chunk_start) { + fprintf(stderr, "Cannot split file (Not enough sync samples, duration too large or size too big)\n"); + goto err_exit; + } + + + /*if not last chunk and longer duration adjust to previous RAP point*/ + if ( (size_exceeded || !split_size_kb) && (file_split_dur>split_dur) && !chunk_start) { + /*if larger than last RAP, rewind till it*/ + if (last_rap_sample_time && (last_rap_sample_timedst_tk); + + time = (Double) (s64) gf_isom_get_media_duration(dest, tki->dst_tk); + //time could get slightly higher than requests dur due to rounding precision. We use 1/4 of the last sample dur as safety marge + time -= (Double) (s64) gf_isom_get_sample_duration(dest, tki->dst_tk, tki->last_sample) / 4; + time /= tki->time_scale; + + if (last_samp<=1) break; + + /*done*/ + if (tki->last_sample==tki->sample_count) { + if (!chunk_extraction && !tki->can_duplicate) { + tki->stop_state=2; + break; + } + } + + if (time <= file_split_dur) break; + + gf_isom_remove_sample(dest, tki->dst_tk, last_samp); + tki->last_sample--; + assert(tki->last_sample); + nb_done--; + gf_set_progress("Splitting", nb_done, nb_samp); + } + if (tki->last_samplesample_count) { + u64 dts; + tki->stop_state = 0; + dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); + time = (Double) (s64) (dts - tki->firstDTS); + time /= tki->time_scale; + /*re-insert prev sample*/ + if (tki->can_duplicate && (time>file_split_dur) ) { + Bool was_insert = GF_FALSE; + tki->last_sample--; + dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); + if (dts < tki->firstDTS) was_insert = GF_TRUE; + tki->firstDTS += (u64) (file_split_dur*tki->time_scale); + //the original, last sample added starts before the first sample in the file: we have re-inserted + //a single sample, use split duration as target duration + if (was_insert) { + gf_isom_set_last_sample_duration(dest, tki->dst_tk, (u32) (file_split_dur*tki->time_scale)); + } else { + gf_isom_set_last_sample_duration(dest, tki->dst_tk, (u32) (tki->firstDTS - dts) ); + } + } else { + tki->firstDTS = dts; + } + tki->first_sample_done = 0; + } else { + nb_tk_done++; + } + + } + } + + if (chunk_extraction) { + fprintf(stderr, "Extracting chunk %s - duration %02.2fs (%02.2fs->%02.2fs)\n", szFile, file_split_dur, chunk_start, (chunk_start+split_dur)); + } else { + fprintf(stderr, "Storing split-file %s - duration %02.2f seconds\n", szFile, file_split_dur); + } + + /*repack CTSs*/ + for (i=0; istop_state == 2) continue; + if (!gf_isom_get_sample_count(dest, tki->dst_tk)) { + gf_isom_remove_track(dest, tki->dst_tk); + continue; + } + if (gf_isom_has_time_offset(mp4, tki->tk)) { + gf_isom_set_cts_packing(dest, tki->dst_tk, 0); + } + if (is_last_rap && tki->can_duplicate) { + gf_isom_set_last_sample_duration(dest, tki->dst_tk, gf_isom_get_sample_duration(mp4, tki->tk, tki->sample_count)); + } + + /*rewrite edit list*/ + new_track_dur = gf_isom_get_track_duration(dest, tki->dst_tk); + count = gf_isom_get_edit_segment_count(mp4, tki->tk); + if (count>2) { + fprintf(stderr, "Warning: %d edit segments - not supported while splitting (max 2) - ignoring extra\n", count); + count=2; + } + for (j=0; jtk, j+1, &editTime, &segDur, &MediaTime, &mode); + if (!j && (mode!=GF_ISOM_EDIT_EMPTY) ) { + fprintf(stderr, "Warning: Edit list doesn't look like a track delay scheme - ignoring\n"); + break; + } + if (mode==GF_ISOM_EDIT_NORMAL) { + segDur = new_track_dur; + } + gf_isom_set_edit_segment(dest, tki->dst_tk, editTime, segDur, MediaTime, mode); + } + } + /*check chapters*/ + do_add = 1; + for (i=0; icur_file_time+file_split_dur) break; + max_dts-=cur_file_time; + chap_time = (u64) (max_dts*1000); + gf_isom_add_chapter(dest, 0, chap_time, name); + /*add prev*/ + if (do_add && i) { + gf_isom_get_chapter(mp4, 0, i, &chap_time, (const char **) &name); + gf_isom_add_chapter(dest, 0, 0, name); + do_add = 0; + } + } + cur_file_time += file_split_dur; + + if (conv_type==1) gf_media_make_isma(dest, 1, 0, 0); + else if (conv_type==2) gf_media_make_3gpp(dest); + if (InterleavingTime) { + gf_isom_make_interleave(dest, InterleavingTime); + } else { + gf_isom_set_storage_mode(dest, GF_ISOM_STORE_STREAMABLE); + } + + gf_isom_clone_pl_indications(mp4, dest); + e = gf_isom_close(dest); + dest = NULL; + if (e) fprintf(stderr, "Error storing file %s\n", gf_error_to_string(e)); + if (is_last_rap || chunk_extraction) break; + cur_file++; + } + gf_set_progress("Splitting", nb_samp, nb_samp); +err_exit: + if (dest) gf_isom_delete(dest); + gf_free(tks); + return e; +} + +GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command); + +static Bool merge_parameter_set(GF_List *src, GF_List *dst, const char *name) +{ + u32 j, k; + for (j=0; jsize==slc_dst->size) && !memcmp(slc->data, slc_dst->data, slc->size) ) { + found = 1; + break; + } + } + if (!found) { + return GF_FALSE; + } + } + return GF_TRUE; +} + +static u32 merge_avc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 src_track, Bool force_cat) +{ + GF_AVCConfig *avc_src, *avc_dst; + u32 dst_tk = gf_isom_get_track_by_id(dest, tk_id); + + avc_src = gf_isom_avc_config_get(orig, src_track, 1); + avc_dst = gf_isom_avc_config_get(dest, dst_tk, 1); + + if (avc_src->AVCLevelIndication!=avc_dst->AVCLevelIndication) { + dst_tk = 0; + } else if (avc_src->AVCProfileIndication!=avc_dst->AVCProfileIndication) { + dst_tk = 0; + } + else { + /*rewrite all samples if using different NALU size*/ + if (avc_src->nal_unit_size > avc_dst->nal_unit_size) { + gf_media_avc_rewrite_samples(dest, dst_tk, 8*avc_dst->nal_unit_size, 8*avc_src->nal_unit_size); + avc_dst->nal_unit_size = avc_src->nal_unit_size; + } else if (avc_src->nal_unit_size < avc_dst->nal_unit_size) { + gf_media_avc_rewrite_samples(orig, src_track, 8*avc_src->nal_unit_size, 8*avc_dst->nal_unit_size); + } + + /*merge PS*/ + if (!merge_parameter_set(avc_src->sequenceParameterSets, avc_dst->sequenceParameterSets, "SPS")) + dst_tk = 0; + if (!merge_parameter_set(avc_src->pictureParameterSets, avc_dst->pictureParameterSets, "PPS")) + dst_tk = 0; + + gf_isom_avc_config_update(dest, dst_tk, 1, avc_dst); + } + + gf_odf_avc_cfg_del(avc_src); + gf_odf_avc_cfg_del(avc_dst); + + if (!dst_tk) { + dst_tk = gf_isom_get_track_by_id(dest, tk_id); + gf_isom_set_nalu_extract_mode(orig, src_track, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG); + if (!force_cat) { + gf_isom_avc_set_inband_config(dest, dst_tk, 1); + } else { + fprintf(stderr, "WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id); + } + } + return dst_tk; +} + +static u32 merge_hevc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 src_track, Bool force_cat) +{ + u32 i; + GF_HEVCConfig *hevc_src, *hevc_dst; + u32 dst_tk = gf_isom_get_track_by_id(dest, tk_id); + + hevc_src = gf_isom_hevc_config_get(orig, src_track, 1); + hevc_dst = gf_isom_hevc_config_get(dest, dst_tk, 1); + + if (hevc_src->profile_idc != hevc_dst->profile_idc) dst_tk = 0; + else if (hevc_src->level_idc != hevc_dst->level_idc) dst_tk = 0; + else if (hevc_src->general_profile_compatibility_flags != hevc_dst->general_profile_compatibility_flags ) dst_tk = 0; + else { + /*rewrite all samples if using different NALU size*/ + if (hevc_src->nal_unit_size > hevc_dst->nal_unit_size) { + gf_media_avc_rewrite_samples(dest, dst_tk, 8*hevc_dst->nal_unit_size, 8*hevc_src->nal_unit_size); + hevc_dst->nal_unit_size = hevc_src->nal_unit_size; + } else if (hevc_src->nal_unit_size < hevc_dst->nal_unit_size) { + gf_media_avc_rewrite_samples(orig, src_track, 8*hevc_src->nal_unit_size, 8*hevc_dst->nal_unit_size); + } + + /*merge PS*/ + for (i=0; iparam_array); i++) { + u32 k; + GF_HEVCParamArray *src_ar = gf_list_get(hevc_src->param_array, i); + for (k=0; kparam_array); k++) { + GF_HEVCParamArray *dst_ar = gf_list_get(hevc_dst->param_array, k); + if (dst_ar->type==src_ar->type) { + if (!merge_parameter_set(src_ar->nalus, dst_ar->nalus, "SPS")) + dst_tk = 0; + break; + } + } + } + + gf_isom_hevc_config_update(dest, dst_tk, 1, hevc_dst); + } + + gf_odf_hevc_cfg_del(hevc_src); + gf_odf_hevc_cfg_del(hevc_dst); + + if (!dst_tk) { + dst_tk = gf_isom_get_track_by_id(dest, tk_id); + gf_isom_set_nalu_extract_mode(orig, src_track, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG); + if (!force_cat) { + gf_isom_hevc_set_inband_config(dest, dst_tk, 1); + } else { + fprintf(stderr, "WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id); + } + } + return dst_tk; +} + +GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command) +{ + u32 i, j, count, nb_tracks, nb_samp, nb_done; + GF_ISOFile *orig; + GF_Err e; + char *opts, *multi_cat; + Double ts_scale; + Double dest_orig_dur; + u32 dst_tk, tk_id, mtype; + u64 insert_dts; + Bool is_isom; + GF_ISOSample *samp; + Double aligned_to_DTS = 0; + + if (strchr(fileName, '*')) return cat_multiple_files(dest, fileName, import_flags, force_fps, frames_per_sample, tmp_dir, force_cat, align_timelines, allow_add_in_command); + + multi_cat = allow_add_in_command ? strchr(fileName, '+') : NULL; + if (multi_cat) { + multi_cat[0] = 0; + multi_cat = &multi_cat[1]; + } + opts = strchr(fileName, ':'); + if (opts && (opts[1]=='\\')) + opts = strchr(fileName, ':'); + + e = GF_OK; + + /*if options are specified, reimport the file*/ + is_isom = opts ? 0 : gf_isom_probe_file(fileName); + + if (!is_isom || opts) { + orig = gf_isom_open("temp", GF_ISOM_WRITE_EDIT, tmp_dir); + e = import_file(orig, fileName, import_flags, force_fps, frames_per_sample); + if (e) return e; + } else { + /*we open the original file in edit mode since we may have to rewrite AVC samples*/ + orig = gf_isom_open(fileName, GF_ISOM_OPEN_EDIT, tmp_dir); + } + + while (multi_cat) { + char *sep = strchr(multi_cat, '+'); + if (sep) sep[0] = 0; + + e = import_file(orig, multi_cat, import_flags, force_fps, frames_per_sample); + if (e) { + gf_isom_delete(orig); + return e; + } + if (!sep) break; + sep[0]=':'; + multi_cat = sep+1; + } + + nb_samp = 0; + nb_tracks = gf_isom_get_track_count(orig); + for (i=0; i1)) { + insert_dts = 2*gf_isom_get_sample_dts(dest, dst_tk, count) - gf_isom_get_sample_dts(dest, dst_tk, count-1); + } else { + insert_dts = dest_track_dur_before_cat; + if (!count) insert_dts = 0; + } + + ts_scale = gf_isom_get_media_timescale(dest, dst_tk); + ts_scale /= gf_isom_get_media_timescale(orig, i+1); + + /*if not a new track, see if we can merge the edit list - this is a crude test that only checks + we have the same edit types*/ + if (nb_edits && (nb_edits == gf_isom_get_edit_segment_count(dest, dst_tk)) ) { + u64 editTime, segmentDuration, mediaTime, dst_editTime, dst_segmentDuration, dst_mediaTime; + u8 dst_editMode, editMode; + u32 j; + merge_edits = 1; + for (j=0; jDTS; + samp->DTS = (u64) (ts_scale * samp->DTS + (new_track ? 0 : insert_dts)); + samp->CTS_Offset = (u32) (samp->CTS_Offset * ts_scale); + + if (gf_isom_is_self_contained(orig, i+1, di)) { + e = gf_isom_add_sample(dest, dst_tk, di, samp); + } else { + u64 offset; + GF_ISOSample *s = gf_isom_get_sample_info(orig, i+1, j+1, &di, &offset); + e = gf_isom_add_sample_reference(dest, dst_tk, di, samp, offset); + gf_isom_sample_del(&s); + } + gf_isom_sample_del(&samp); + if (e) + goto err_exit; + gf_set_progress("Appending", nb_done, nb_samp); + nb_done++; + } + /*scene description and text: compute last sample duration based on original media duration*/ + if (!use_ts_dur) { + insert_dts = gf_isom_get_media_duration(orig, i+1) - last_DTS; + gf_isom_set_last_sample_duration(dest, dst_tk, (u32) insert_dts); + } + + if (new_track && insert_dts) { + u64 media_dur = gf_isom_get_media_duration(orig, i+1); + /*convert from media time to track time*/ + Double rescale = (Float) gf_isom_get_timescale(dest); + rescale /= (Float) gf_isom_get_media_timescale(dest, dst_tk); + /*convert from orig to dst time scale*/ + rescale *= ts_scale; + + gf_isom_set_edit_segment(dest, dst_tk, 0, (u64) (s64) (insert_dts*rescale), 0, GF_ISOM_EDIT_EMPTY); + gf_isom_set_edit_segment(dest, dst_tk, (u64) (s64) (insert_dts*rescale), (u64) (s64) (media_dur*rescale), 0, GF_ISOM_EDIT_NORMAL); + } else if (merge_edits) { + /*convert from media time to track time*/ + Double rescale = (Float) gf_isom_get_timescale(dest); + rescale /= (Float) gf_isom_get_media_timescale(dest, dst_tk); + /*convert from orig to dst time scale*/ + rescale *= ts_scale; + + /*get the first edit normal mode and add the new track dur*/ + for (j=nb_edits; j>0; j--) { + u64 editTime, segmentDuration, mediaTime; + u8 editMode; + gf_isom_get_edit_segment(dest, dst_tk, j, &editTime, &segmentDuration, &mediaTime, &editMode); + + if (editMode==GF_ISOM_EDIT_NORMAL) { + Double prev_dur = (Double) (s64) dest_track_dur_before_cat; + Double dur = (Double) (s64) gf_isom_get_media_duration(orig, i+1); + + dur *= rescale; + prev_dur *= rescale; + + /*safety test: some files have broken edit lists. If no more than 2 entries, check that the segment duration + is less or equal to the movie duration*/ + if (prev_dur < segmentDuration) { + fprintf(stderr, "Warning: suspicious edit list entry found: duration %g sec but longest track duration before cat is %g - fixing it\n", (Double) (s64) segmentDuration/1000.0, prev_dur/1000); + segmentDuration = (u64) (s64) ( (Double) (s64) (dest_track_dur_before_cat - mediaTime) * rescale ); + } + + segmentDuration += (u64) (s64) dur; + gf_isom_modify_edit_segment(dest, dst_tk, j, segmentDuration, mediaTime, editMode); + break; + } + } + } else { + u64 editTime, segmentDuration, mediaTime, edit_offset; + Double t; + u8 editMode; + u32 j, count; + + count = gf_isom_get_edit_segment_count(dest, dst_tk); + if (count) { + e = gf_isom_get_edit_segment(dest, dst_tk, count, &editTime, &segmentDuration, &mediaTime, &editMode); + if (e) { + fprintf(stderr, "Error: edit segment error on destination track %u could not be retrieved.\n", dst_tk); + goto err_exit; + } + } else if (gf_isom_get_edit_segment_count(orig, i+1)) { + /*fake empty edit segment*/ + /*convert from media time to track time*/ + Double rescale = (Float) gf_isom_get_timescale(dest); + rescale /= (Float) gf_isom_get_media_timescale(dest, dst_tk); + segmentDuration = (u64) (dest_track_dur_before_cat * rescale); + editTime = 0; + mediaTime = 0; + gf_isom_set_edit_segment(dest, dst_tk, editTime, segmentDuration, mediaTime, GF_ISOM_EDIT_NORMAL); + } else { + editTime = 0; + segmentDuration = 0; + } + + /*convert to dst time scale*/ + ts_scale = (Float) gf_isom_get_timescale(dest); + ts_scale /= (Float) gf_isom_get_timescale(orig); + + edit_offset = editTime + segmentDuration; + count = gf_isom_get_edit_segment_count(orig, i+1); + for (j=0; j 0)) { + editMode = GF_ISOM_EDIT_NORMAL; + } + gf_isom_set_edit_segment(dest, dst_tk, editTime, segmentDuration, mediaTime, editMode); + } + } + + } + gf_set_progress("Appending", nb_samp, nb_samp); + + /*check chapters*/ + for (i=0; iszRad1); + if (strnicmp(szName, cat_enum->szRad1, len_rad1)) return 0; + if (strlen(cat_enum->szRad2) && !strstr(szName + len_rad1, cat_enum->szRad2) ) return 0; + + strcpy(szFileName, szName); + strcat(szFileName, cat_enum->szOpt); + + e = cat_isomedia_file(cat_enum->dest, szFileName, cat_enum->import_flags, cat_enum->force_fps, cat_enum->frames_per_sample, cat_enum->tmp_dir, cat_enum->force_cat, cat_enum->align_timelines, cat_enum->allow_add_in_command); + if (e) return 1; + return 0; +} + +GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command) +{ + CATEnum cat_enum; + char *sep; + + cat_enum.dest = dest; + cat_enum.import_flags = import_flags; + cat_enum.force_fps = force_fps; + cat_enum.frames_per_sample = frames_per_sample; + cat_enum.tmp_dir = tmp_dir; + cat_enum.force_cat = force_cat; + cat_enum.align_timelines = align_timelines; + cat_enum.allow_add_in_command = allow_add_in_command; + + strcpy(cat_enum.szPath, fileName); + sep = strrchr(cat_enum.szPath, GF_PATH_SEPARATOR); + if (!sep) sep = strrchr(cat_enum.szPath, '/'); + if (!sep) { + strcpy(cat_enum.szPath, "."); + strcpy(cat_enum.szRad1, fileName); + } else { + strcpy(cat_enum.szRad1, sep+1); + sep[0] = 0; + } + sep = strchr(cat_enum.szRad1, '*'); + strcpy(cat_enum.szRad2, sep+1); + sep[0] = 0; + sep = strchr(cat_enum.szRad2, '%'); + if (!sep) sep = strchr(cat_enum.szRad2, '#'); + if (!sep) sep = strchr(cat_enum.szRad2, ':'); + strcpy(cat_enum.szOpt, ""); + if (sep) { + strcpy(cat_enum.szOpt, sep); + sep[0] = 0; + } + return gf_enum_directory(cat_enum.szPath, 0, cat_enumerate, &cat_enum, NULL); +} + + +#ifndef GPAC_DISABLE_SCENE_ENCODER +/* + MPEG-4 encoding +*/ + +GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *logs) +{ +#ifdef GPAC_DISABLE_SMGR + return GF_NOT_SUPPORTED; +#else + GF_Err e; + GF_SceneLoader load; + GF_SceneManager *ctx; + GF_SceneGraph *sg; +#ifndef GPAC_DISABLE_SCENE_STATS + GF_StatManager *statsman = NULL; +#endif + + sg = gf_sg_new(); + ctx = gf_sm_new(sg); + memset(&load, 0, sizeof(GF_SceneLoader)); + load.fileName = in; + load.ctx = ctx; + load.swf_import_flags = swf_flags; + load.swf_flatten_limit = swf_flatten_angle; + /*since we're encoding we must get MPEG4 nodes only*/ + load.flags = GF_SM_LOAD_MPEG4_STRICT; + e = gf_sm_load_init(&load); + if (e<0) { + gf_sm_load_done(&load); + fprintf(stderr, "Cannot load context %s - %s\n", in, gf_error_to_string(e)); + goto err_exit; + } + e = gf_sm_load_run(&load); + gf_sm_load_done(&load); + +#ifndef GPAC_DISABLE_SCENE_STATS + if (opts->auto_quant) { + fprintf(stderr, "Analysing Scene for Automatic Quantization\n"); + statsman = gf_sm_stats_new(); + e = gf_sm_stats_for_scene(statsman, ctx); + if (!e) { + GF_SceneStatistics *stats = gf_sm_stats_get(statsman); + /*LASeR*/ + if (opts->auto_quant==1) { + if (opts->resolution > (s32)stats->frac_res_2d) { + fprintf(stderr, " Given resolution %d is (unnecessarily) too high, using %d instead.\n", opts->resolution, stats->frac_res_2d); + opts->resolution = stats->frac_res_2d; + } else if (stats->int_res_2d + opts->resolution <= 0) { + fprintf(stderr, " Given resolution %d is too low, using %d instead.\n", opts->resolution, stats->int_res_2d - 1); + opts->resolution = 1 - stats->int_res_2d; + } + opts->coord_bits = stats->int_res_2d + opts->resolution; + fprintf(stderr, " Coordinates & Lengths encoded using "); + if (opts->resolution < 0) fprintf(stderr, "only the %d most significant bits (of %d).\n", opts->coord_bits, stats->int_res_2d); + else fprintf(stderr, "a %d.%d representation\n", stats->int_res_2d, opts->resolution); + + fprintf(stderr, " Matrix Scale & Skew Coefficients "); + if (opts->coord_bits - 8 < stats->scale_int_res_2d) { + opts->scale_bits = stats->scale_int_res_2d - opts->coord_bits + 8; + fprintf(stderr, "encoded using a %d.8 representation\n", stats->scale_int_res_2d); + } else { + opts->scale_bits = 0; + fprintf(stderr, "encoded using a %d.8 representation\n", opts->coord_bits - 8); + } + } +#ifndef GPAC_DISABLE_VRML + /*BIFS*/ + else if (stats->base_layer) { + GF_AUContext *au; + GF_CommandField *inf; + M_QuantizationParameter *qp; + GF_Command *com = gf_sg_command_new(ctx->scene_graph, GF_SG_GLOBAL_QUANTIZER); + qp = (M_QuantizationParameter *) gf_node_new(ctx->scene_graph, TAG_MPEG4_QuantizationParameter); + + inf = gf_sg_command_field_new(com); + inf->new_node = (GF_Node *)qp; + inf->field_ptr = &inf->new_node; + inf->fieldType = GF_SG_VRML_SFNODE; + gf_node_register(inf->new_node, NULL); + au = gf_list_get(stats->base_layer->AUs, 0); + gf_list_insert(au->commands, com, 0); + qp->useEfficientCoding = 1; + qp->textureCoordinateQuant = 0; + if ((stats->count_2f+stats->count_2d) && opts->resolution) { + qp->position2DMin = stats->min_2d; + qp->position2DMax = stats->max_2d; + qp->position2DNbBits = opts->resolution; + qp->position2DQuant = 1; + } + if ((stats->count_3f+stats->count_3d) && opts->resolution) { + qp->position3DMin = stats->min_3d; + qp->position3DMax = stats->max_3d; + qp->position3DQuant = opts->resolution; + qp->position3DQuant = 1; + qp->textureCoordinateQuant = 1; + } + if (0 && stats->count_float && opts->resolution) { + qp->scaleMin = stats->min_fixed; + qp->scaleMax = stats->max_fixed; + qp->scaleNbBits = 2*opts->resolution; + qp->scaleQuant = 1; + } + } +#endif + } + } +#endif /*GPAC_DISABLE_SCENE_STATS*/ + + if (e<0) { + fprintf(stderr, "Error loading file %s\n", gf_error_to_string(e)); + goto err_exit; + } else { + gf_log_cbk prev_logs = NULL; + if (logs) { + gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_DEBUG); + prev_logs = gf_log_set_callback(logs, scene_coding_log); + } + opts->src_url = in; + e = gf_sm_encode_to_file(ctx, mp4, opts); + if (logs) { + gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_ERROR); + gf_log_set_callback(NULL, prev_logs); + } + } + + gf_isom_set_brand_info(mp4, GF_ISOM_BRAND_MP42, 1); + gf_isom_modify_alternate_brand(mp4, GF_ISOM_BRAND_ISOM, 1); + +err_exit: +#ifndef GPAC_DISABLE_SCENE_STATS + if (statsman) gf_sm_stats_del(statsman); +#endif + gf_sm_del(ctx); + gf_sg_del(sg); + return e; + +#endif /*GPAC_DISABLE_SMGR*/ +} +#endif /*GPAC_DISABLE_SCENE_ENCODER*/ + + +#ifndef GPAC_DISABLE_BIFS_ENC +/* + MPEG-4 chunk encoding +*/ + +static u32 GetNbBits(u32 MaxVal) +{ + u32 k=0; + while ((s32) MaxVal > ((1<streams starting at AU index 1 (0 is SceneReplace from previous context) */ + bifsenc = gf_bifs_encoder_new(ctx->scene_graph); + e = GF_OK; + + iod = (GF_InitialObjectDescriptor *) ctx->root_od; + /*if no iod check we only have one bifs*/ + if (!iod) { + count = 0; + for (i=0; istreams); i++) { + sc = gf_list_get(ctx->streams, i); + if (sc->streamType == GF_STREAM_OD) count++; + } + if (!iod && count>1) return GF_NOT_SUPPORTED; + } + + count = gf_list_count(ctx->streams); + + for (i=0; istreams); i++) { + u32 nbb; + GF_StreamContext *sc = gf_list_get(ctx->streams, i); + esd = NULL; + if (sc->streamType != GF_STREAM_SCENE) continue; + + esd = NULL; + if (iod) { + for (j=0; jESDescriptors); j++) { + esd = gf_list_get(iod->ESDescriptors, j); + if (esd->decoderConfig && esd->decoderConfig->streamType == GF_STREAM_SCENE) { + if (!sc->ESID) sc->ESID = esd->ESID; + if (sc->ESID == esd->ESID) { + break; + } + } + /*special BIFS direct import from NHNT*/ + else if (gf_list_count(iod->ESDescriptors)==1) { + sc->ESID = esd->ESID; + break; + } + esd = NULL; + } + } + + if (!esd) { + esd = gf_odf_desc_esd_new(2); + gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); + esd->decoderConfig->decoderSpecificInfo = NULL; + esd->ESID = sc->ESID; + esd->decoderConfig->streamType = GF_STREAM_SCENE; + } + + /*should NOT happen (means inputctx is not properly setup)*/ + if (!esd->decoderConfig->decoderSpecificInfo) { + bcfg = (GF_BIFSConfig*)gf_odf_desc_new(GF_ODF_BIFS_CFG_TAG); + delete_bcfg = 1; + } + /*regular retrieve from ctx*/ + else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_BIFS_CFG_TAG) { + bcfg = (GF_BIFSConfig *)esd->decoderConfig->decoderSpecificInfo; + delete_bcfg = 0; + } + /*should not happen either (unless loading from MP4 in which case BIFSc is not decoded)*/ + else { + bcfg = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication); + delete_bcfg = 1; + } + /*NO CHANGE TO BIFSC otherwise the generated update will not match the input context*/ + nbb = GetNbBits(ctx->max_node_id); + if (!bcfg->nodeIDbits) bcfg->nodeIDbits=nbb; + if (bcfg->nodeIDbitsmax_route_id); + if (!bcfg->routeIDbits) bcfg->routeIDbits = nbb; + if (bcfg->routeIDbitsmax_proto_id); + if (!bcfg->protoIDbits) bcfg->protoIDbits=nbb; + if (bcfg->protoIDbitsESID, bcfg, encode_names, 0); + if (delete_bcfg) gf_odf_desc_del((GF_Descriptor *)bcfg); + + /*setup MP4 track*/ + if (!esd->slConfig) esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); + if (sc->timeScale) esd->slConfig->timestampResolution = sc->timeScale; + if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000; + esd->ESID = sc->ESID; + gf_bifs_encoder_get_config(bifsenc, sc->ESID, &data, &data_len); + + if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); + esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); + esd->decoderConfig->decoderSpecificInfo->data = data; + esd->decoderConfig->decoderSpecificInfo->dataLength = data_len; + esd->decoderConfig->objectTypeIndication = gf_bifs_encoder_get_version(bifsenc, sc->ESID); + + for (j=1; jAUs); j++) { + char *data; + u32 data_len; + au = gf_list_get(sc->AUs, j); + e = gf_bifs_encode_au(bifsenc, sc->ESID, au->commands, &data, &data_len); + if (data) { + sprintf(szName, "%s%02d.bifs", szRad, j); + f = gf_fopen(szName, "wb"); + gf_fwrite(data, data_len, 1, f); + gf_fclose(f); + gf_free(data); + } + } + } + gf_bifs_encoder_del(bifsenc); + return e; +} +#endif /*GPAC_DISABLE_SMGR*/ + + +#endif /*GPAC_DISABLE_BIFS_ENC*/ + +/** + * \param chunkFile BT chunk to be encoded + * \param bifs output file name for the BIFS data + * \param inputContext initial BT upon which the chunk is based (shall not be NULL) + * \param outputContext: file name to dump the context after applying the new chunk to the input context + can be NULL, without .bt + * \param tmpdir can be NULL + */ +GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *outputContext, const char *tmpdir) +{ +#if defined(GPAC_DISABLE_SMGR) || defined(GPAC_DISABLE_BIFS_ENC) || defined(GPAC_DISABLE_SCENE_ENCODER) || defined (GPAC_DISABLE_SCENE_DUMP) + fprintf(stderr, "BIFS encoding is not supported in this build of GPAC\n"); + return GF_NOT_SUPPORTED; +#else + GF_Err e; + GF_SceneGraph *sg; + GF_SceneManager *ctx; + GF_SceneLoader load; + + /*Step 1: create context and load input*/ + sg = gf_sg_new(); + ctx = gf_sm_new(sg); + memset(&load, 0, sizeof(GF_SceneLoader)); + load.fileName = inputContext; + load.ctx = ctx; + /*since we're encoding we must get MPEG4 nodes only*/ + load.flags = GF_SM_LOAD_MPEG4_STRICT; + e = gf_sm_load_init(&load); + if (!e) e = gf_sm_load_run(&load); + gf_sm_load_done(&load); + if (e) { + fprintf(stderr, "Cannot load context %s - %s\n", inputContext, gf_error_to_string(e)); + goto exit; + } + + /* Step 2: make sure we have only ONE RAP for each stream*/ + e = gf_sm_aggregate(ctx, 0); + if (e) goto exit; + + /*Step 3: loading the chunk into the context*/ + memset(&load, 0, sizeof(GF_SceneLoader)); + load.fileName = chunkFile; + load.ctx = ctx; + load.flags = GF_SM_LOAD_MPEG4_STRICT | GF_SM_LOAD_CONTEXT_READY; + e = gf_sm_load_init(&load); + if (!e) e = gf_sm_load_run(&load); + gf_sm_load_done(&load); + if (e) { + fprintf(stderr, "Cannot load chunk context %s - %s\n", chunkFile, gf_error_to_string(e)); + goto exit; + } + fprintf(stderr, "Context and chunks loaded\n"); + + /* Assumes that the first AU contains only one command a SceneReplace and + that is not part of the current chunk */ + /* Last argument is a callback to pass the encoded AUs: not needed here + Saving is not handled correctly */ + e = EncodeBIFSChunk(ctx, bifs, NULL); + if (e) goto exit; + + + if (outputContext) { + u32 d_mode, do_enc; + char szF[GF_MAX_PATH], *ext; + + /*make random access for storage*/ + e = gf_sm_aggregate(ctx, 0); + if (e) goto exit; + + /*check if we dump to BT, XMT or encode to MP4*/ + strcpy(szF, outputContext); + ext = strrchr(szF, '.'); + d_mode = GF_SM_DUMP_BT; + do_enc = 0; + if (ext) { + if (!stricmp(ext, ".xmt") || !stricmp(ext, ".xmta")) d_mode = GF_SM_DUMP_XMTA; + else if (!stricmp(ext, ".mp4")) do_enc = 1; + ext[0] = 0; + } + + if (do_enc) { + GF_ISOFile *mp4; + strcat(szF, ".mp4"); + mp4 = gf_isom_open(szF, GF_ISOM_WRITE_EDIT, tmpdir); + e = gf_sm_encode_to_file(ctx, mp4, NULL); + if (e) gf_isom_delete(mp4); + else gf_isom_close(mp4); + } + else e = gf_sm_dump(ctx, szF, d_mode); + } + +exit: + if (ctx) { + sg = ctx->scene_graph; + gf_sm_del(ctx); + gf_sg_del(sg); + } + + return e; + +#endif /*defined(GPAC_DISABLE_BIFS_ENC) || defined(GPAC_DISABLE_SCENE_ENCODER) || defined (GPAC_DISABLE_SCENE_DUMP)*/ + +} + +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ + + +#ifndef GPAC_DISABLE_CORE_TOOLS +void sax_node_start(void *sax_cbck, const char *node_name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes) +{ + char szCheck[100]; + GF_List *imports = sax_cbck; + GF_XMLAttribute *att; + u32 i=0; + + /*do not process hyperlinks*/ + if (!strcmp(node_name, "a") || !strcmp(node_name, "Anchor")) return; + + for (i=0; iname, "xlink:href") && stricmp(att->name, "url")) continue; + if (att->value[0]=='#') continue; + if (!strnicmp(att->value, "od:", 3)) continue; + sprintf(szCheck, "%d", atoi(att->value)); + if (!strcmp(szCheck, att->value)) continue; + gf_list_add(imports, gf_strdup(att->value) ); + } +} + +static Bool wgt_enum_files(void *cbck, char *file_name, char *file_path, GF_FileEnumInfo *file_info) +{ + WGTEnum *wgt = (WGTEnum *)cbck; + + if (!strcmp(wgt->root_file, file_path)) return 0; + /*remove CVS stuff*/ + if (strstr(file_path, ".#")) return 0; + gf_list_add(wgt->imports, gf_strdup(file_path) ); + return 0; +} +static Bool wgt_enum_dir(void *cbck, char *file_name, char *file_path, GF_FileEnumInfo *file_info) +{ + if (!stricmp(file_name, "cvs") || !stricmp(file_name, ".svn") || !stricmp(file_name, ".git")) return 0; + gf_enum_directory(file_path, 0, wgt_enum_files, cbck, NULL); + return gf_enum_directory(file_path, 1, wgt_enum_dir, cbck, NULL); +} + +GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool make_wgt) +{ + GF_ISOFile *file = NULL; + GF_Err e; + GF_SAXParser *sax; + GF_List *imports; + Bool ascii; + char root_dir[GF_MAX_PATH]; + char *isom_src = NULL; + u32 i, count, mtype, skip_chars; + char *type; + + type = gf_xml_get_root_type(file_name, &e); + if (!type) { + fprintf(stderr, "Cannot process XML file %s: %s\n", file_name, gf_error_to_string(e) ); + return NULL; + } + if (make_wgt) { + if (strcmp(type, "widget")) { + fprintf(stderr, "XML Root type %s differs from \"widget\" \n", type); + gf_free(type); + return NULL; + } + gf_free(type); + type = gf_strdup("application/mw-manifest+xml"); + fcc = "mwgt"; + } + imports = gf_list_new(); + + + root_dir[0] = 0; + if (make_wgt) { + WGTEnum wgt; + char *sep = strrchr(file_name, '\\'); + if (!sep) sep = strrchr(file_name, '/'); + if (sep) { + char c = sep[1]; + sep[1]=0; + strcpy(root_dir, file_name); + sep[1] = c; + } else { + strcpy(root_dir, "./"); + } + wgt.dir = root_dir; + wgt.root_file = file_name; + wgt.imports = imports; + gf_enum_directory(wgt.dir, 0, wgt_enum_files, &wgt, NULL); + gf_enum_directory(wgt.dir, 1, wgt_enum_dir, &wgt, NULL); + ascii = 1; + } else { + sax = gf_xml_sax_new(sax_node_start, NULL, NULL, imports); + e = gf_xml_sax_parse_file(sax, file_name, NULL); + ascii = !gf_xml_sax_binary_file(sax); + gf_xml_sax_del(sax); + if (e<0) goto exit; + e = GF_OK; + } + + if (fcc) { + mtype = GF_4CC(fcc[0],fcc[1],fcc[2],fcc[3]); + } else { + mtype = 0; + if (!stricmp(type, "svg")) mtype = ascii ? GF_4CC('s','v','g',' ') : GF_4CC('s','v','g','z'); + else if (!stricmp(type, "smil")) mtype = ascii ? GF_4CC('s','m','i','l') : GF_4CC('s','m','l','z'); + else if (!stricmp(type, "x3d")) mtype = ascii ? GF_4CC('x','3','d',' ') : GF_4CC('x','3','d','z') ; + else if (!stricmp(type, "xmt-a")) mtype = ascii ? GF_4CC('x','m','t','a') : GF_4CC('x','m','t','z'); + } + if (!mtype) { + fprintf(stderr, "Missing 4CC code for meta name - please use ABCD:fileName\n"); + e = GF_BAD_PARAM; + goto exit; + } + + + if (!make_wgt) { + count = gf_list_count(imports); + for (i=0; i +#include + +#ifndef GPAC_DISABLE_SENG +#include +#endif +#ifndef GPAC_DISABLE_STREAMING +#include +#include +#endif + +#include + +#ifndef GPAC_DISABLE_STREAMING +#include +#endif + +#if defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE) + +#error "Cannot compile MP4Box if GPAC is not built with ISO File Format support" + +#else + +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + +void PrintStreamerUsage() +{ + fprintf(stderr, "File Streamer Options\n" + "\n" + "MP4Box can stream ISO files to RTP. The streamer currently doesn't support\n" + "data carrouselling and will therefore not handle BIFS and OD streams properly.\n" + "\n" + "-rtp enables streamer\n" + "-noloop disables looping when streaming\n" + "-mpeg4 forces MPEG-4 ES Generic for all RTP streams\n" + "-dst=IP IP destination (uni/multi-cast). Default: 127.0.0.1\n" + "-port=PORT output port of the first stream. Default: 7000\n" + "-mtu=MTU path MTU for RTP packets. Default is 1450 bytes\n" + "-ifce=IFCE IP address of the physical interface to use. Default: NULL (ANY)\n" + "-ttl=TTL time to live for multicast packets. Default: 1\n" + "-sdp=Name file name of the generated SDP. Default: \"session.sdp\"\n" + "\n" + ); +} + +static void on_logs(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) +{ + FILE *logs = cbk; + vfprintf(logs, fmt, list); + fflush(logs); +} + +int stream_file_rtp(int argc, char **argv) +{ + GF_ISOMRTPStreamer *file_streamer; + char *sdp_file = "session.sdp"; + char *ip_dest = "127.0.0.1"; + char *ifce_addr = NULL; + char *inName = NULL; + char *logs=NULL; + FILE *logfile=NULL; + u16 port = 7000; + u32 ttl = 1; + Bool loop = 1; + Bool mem_track = 0; + Bool force_mpeg4 = 0; + u32 path_mtu = 1450; + u32 i; + + for (i = 1; i < (u32) argc ; i++) { + char *arg = argv[i]; + + if (arg[0] != '-') { + if (inName) { + fprintf(stderr, "Error - 2 input names specified, please check usage\n"); + return 1; + } + inName = arg; + } + else if (!stricmp(arg, "-noloop")) loop = 0; + else if (!stricmp(arg, "-mpeg4")) force_mpeg4 = 1; + else if (!strnicmp(arg, "-port=", 6)) port = atoi(arg+6); + else if (!strnicmp(arg, "-mtu=", 5)) path_mtu = atoi(arg+5); + else if (!strnicmp(arg, "-dst=", 5)) ip_dest = arg+5; + else if (!strnicmp(arg, "-ttl=", 5)) ttl = atoi(arg+5); + else if (!strnicmp(arg, "-ifce=", 6)) ifce_addr = arg+6; + else if (!strnicmp(arg, "-sdp=", 5)) sdp_file = arg+5; + else if (!stricmp(arg, "-mem-track")) mem_track = 1; + else if (!strnicmp(arg, "-logs=", 6)) logs = arg+6; + else if (!strnicmp(arg, "-lf=", 4)) logfile = gf_fopen(arg+4, "wt"); + } + + gf_sys_init(mem_track); + if (logs) + gf_log_set_tools_levels(logs); + else + gf_log_set_tool_level(GF_LOG_RTP, GF_LOG_INFO); //set to debug to have packet list + if (logfile) { + gf_log_set_callback(logfile, on_logs); + } + + if (!gf_isom_probe_file(inName)) { + fprintf(stderr, "File %s is not a valid ISO Media file and cannot be streamed\n", inName); + if (logfile) gf_fclose(logfile); + gf_sys_close(); + return 1; + } + + file_streamer = gf_isom_streamer_new(inName, ip_dest, port, loop, force_mpeg4, path_mtu, ttl, ifce_addr); + if (!file_streamer) { + fprintf(stderr, "Cannot create file streamer\n"); + } else { + u32 check = 50; + fprintf(stderr, "Starting streaming %s to %s:%d\n", inName, ip_dest, port); + gf_isom_streamer_write_sdp(file_streamer, sdp_file); + + while (1) { + gf_isom_streamer_send_next_packet(file_streamer, 0, 0); + check--; + if (!check) { + if (gf_prompt_has_input()) { + char c = (char) gf_prompt_get_char(); + if (c=='q') break; + } + check = 50; + } + } + gf_isom_streamer_del(file_streamer); + } + if (logfile) gf_fclose(logfile); + gf_sys_close(); + return 0; +} + + +void PrintLiveUsage() +{ + fprintf(stderr, + + "Live scene encoder options:\n" + "-dst=IP destination IP - default: NULL\n" + "-port=PORT destination port - default: 7000\n" + "-mtu=MTU path MTU for RTP packets. Default is 1450 bytes\n" + "-ifce=IFCE IP address of the physical interface to use. Default: NULL(ANY)\n" + "-ttl=TTL time to live for multicast packets. Default: 1\n" + "-sdp=Name ouput SDP file - default: session.sdp\n" + "\n" + "-dims turns on DIMS mode for SVG input - default: off\n" + "-no-rap disabled RAP sending - this also disables carousel generation. Default: off\n" + "-src=file source of updates - default: null\n" + "-rap=time duration in ms of base carousel - default: 0 (off)\n" + " you can specify the RAP period of a single ESID (not in DIMS):\n" + " -rap=ESID=X:time\n" + "\n" + "Runtime options:\n" + "q: quits\n" + "u: inputs some commands to be sent\n" + "U: same as u but signals the updates as critical\n" + "e: inputs some commands to be sent without being aggregated\n" + "E: same as e but signals the updates as critical\n" + "f: forces RAP sending\n" + "F: forces RAP regeneration and sending\n" + "p: dumps current scene\n" + "\n" + "GPAC version: " GPAC_FULL_VERSION "\n" + ""); +} +typedef struct +{ + GF_RTPStreamer *rtp; + Bool manual_rtcp; + u16 ESID; + + char *carousel_data; + u32 carousel_size, carousel_alloc; + u32 last_carousel_time; + u64 carousel_ts, time_at_carousel_store; + + u32 timescale, init_time; + u32 carousel_period, ts_delta; + u16 aggregate_on_stream; + Bool adjust_carousel_time, discard, aggregate, rap, m2ts_vers_inc; + u32 critical; +} RTPChannel; + +typedef struct +{ + GF_SceneEngine *seng; + Bool force_carousel, carousel_generation; + GF_List *streams; + u32 start_time; + Bool critical; +} LiveSession; + + +RTPChannel *next_carousel(LiveSession *sess, u32 *timeout) +{ + RTPChannel *to_send = NULL; + u32 i, time, count, now; + + if (!sess->start_time) sess->start_time = gf_sys_clock(); + now = gf_sys_clock() - sess->start_time; + + time = (u32) -1; + count = gf_list_count(sess->streams); + for (i=0; istreams, i); + if (!ch->carousel_period) continue; + if (!ch->carousel_size) continue; + + if (!ch->last_carousel_time) ch->last_carousel_time = now; + + if (ch->last_carousel_time + ch->carousel_period < time) { + to_send = ch; + time = ch->last_carousel_time + ch->carousel_period; + } + } + if (!to_send) { + if (timeout) *timeout = 0; + return NULL; + } + if (timeout) { + if (time>now) time-=now; + else time=0; + *timeout = time; + } + return to_send; +} + + +static void live_session_callback(void *calling_object, u16 ESID, char *data, u32 size, u64 ts) +{ + LiveSession *livesess = (LiveSession *) calling_object; + RTPChannel *rtpch; + u32 i=0; + + while ( (rtpch = gf_list_enum(livesess->streams, &i))) { + if (rtpch->ESID == ESID) { + + /*store carousel data*/ + if (livesess->carousel_generation && rtpch->carousel_period) { + if (rtpch->carousel_alloc < size) { + rtpch->carousel_data = gf_realloc(rtpch->carousel_data, size); + rtpch->carousel_alloc = size; + } + memcpy(rtpch->carousel_data, data, size); + rtpch->carousel_size = size; + rtpch->carousel_ts = ts; + rtpch->time_at_carousel_store = gf_sys_clock(); + fprintf(stderr, "\nStream %d: Storing new carousel TS "LLD", %d bytes\n", ESID, ts, size); + } + /*send data*/ + else { + u32 critical = 0; + Bool rap = rtpch->rap; + if (livesess->carousel_generation) rap = 1; + ts += rtpch->timescale*((u64)gf_sys_clock()-rtpch->init_time + rtpch->ts_delta)/1000; + if (rtpch->critical) critical = rtpch->critical; + else if (livesess->critical) critical = 1; + + gf_rtp_streamer_send_au_with_sn(rtpch->rtp, data, size, ts, ts, rap, critical); + + fprintf(stderr, "Stream %d: Sending update at TS "LLD", %d bytes - RAP %d - critical %d\n", ESID, ts, size, rap, critical); + rtpch->rap = rtpch->critical = 0; + + if (rtpch->manual_rtcp) gf_rtp_streamer_send_rtcp(rtpch->rtp, 0, 0, 0, 0, 0); + } + return; + } + } +} + +static void live_session_send_carousel(LiveSession *livesess, RTPChannel *ch) +{ + u32 now = gf_sys_clock(); + u64 ts=0; + if (ch) { + if (ch->carousel_size) { + ts = ch->carousel_ts + ch->timescale * ( (ch->adjust_carousel_time ? (u64)gf_sys_clock() : ch->time_at_carousel_store) - ch->init_time + ch->ts_delta)/1000; + + gf_rtp_streamer_send_au_with_sn(ch->rtp, ch->carousel_data, ch->carousel_size, ts, ts, 1, 0); + ch->last_carousel_time = now - livesess->start_time; + fprintf(stderr, "Stream %d: Sending carousel at TS "LLD", %d bytes\n", ch->ESID, ts, ch->carousel_size); + + if (ch->manual_rtcp) { + ts = ch->carousel_ts + ch->timescale * ( gf_sys_clock() - ch->init_time + ch->ts_delta)/1000; + gf_rtp_streamer_send_rtcp(ch->rtp, 1, (u32) ts, 0, 0, 0); + } + } + } else { + u32 i=0; + while (NULL != (ch = gf_list_enum(livesess->streams, &i))) { + if (ch->carousel_size) { + if (ch->adjust_carousel_time) { + ts = ch->carousel_ts + ch->timescale*(gf_sys_clock()-ch->init_time + ch->ts_delta)/1000; + } else { + ts = ch->carousel_ts; + } + gf_rtp_streamer_send_au_with_sn(ch->rtp, ch->carousel_data, ch->carousel_size, ts, ts, 1, 0); + ch->last_carousel_time = now - livesess->start_time; + fprintf(stderr, "Stream %d: Sending carousel at TS "LLD" , %d bytes\n", ch->ESID, ts, ch->carousel_size); + + if (ch->manual_rtcp) { + ts = ch->carousel_ts + ch->timescale*(gf_sys_clock()-ch->init_time + ch->ts_delta)/1000; + gf_rtp_streamer_send_rtcp(ch->rtp, 1, (u32) ts, 0, 0, 0); + } + } + } + } +} + +static void live_session_setup(LiveSession *livesess, char *ip, u16 port, u32 path_mtu, u32 ttl, char *ifce_addr, char *sdp_name) +{ + RTPChannel *rtpch; + u32 count = gf_seng_get_stream_count(livesess->seng); + u32 i; + char *iod64 = gf_seng_get_base64_iod(livesess->seng); + char *sdp = gf_rtp_streamer_format_sdp_header("GPACSceneStreamer", ip, NULL, iod64); + if (iod64) gf_free(iod64); + + for (i=0; iseng, i, &ESID, &config, &config_len, &st, &oti, &ts); + + GF_SAFEALLOC(rtpch, RTPChannel); + rtpch->timescale = ts; + rtpch->init_time = gf_sys_clock(); + + switch (st) { + case GF_STREAM_OD: + case GF_STREAM_SCENE: + rtpch->rtp = gf_rtp_streamer_new_extended(st, oti, ts, ip, port, path_mtu, ttl, ifce_addr, + GP_RTP_PCK_SYSTEMS_CAROUSEL, (char *) config, config_len, + 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4); + + if (rtpch->rtp) { + gf_rtp_streamer_disable_auto_rtcp(rtpch->rtp); + rtpch->manual_rtcp = 1; + } + break; + default: + rtpch->rtp = gf_rtp_streamer_new(st, oti, ts, ip, port, path_mtu, ttl, ifce_addr, GP_RTP_PCK_SIGNAL_RAP, (char *) config, config_len); + break; + } + rtpch->ESID = ESID; + rtpch->adjust_carousel_time = 1; + gf_list_add(livesess->streams, rtpch); + + gf_rtp_streamer_append_sdp(rtpch->rtp, ESID, (char *) config, config_len, NULL, &sdp); + + /*fetch initial config of the broadcast*/ + gf_seng_get_stream_carousel_info(livesess->seng, ESID, &rtpch->carousel_period, &rtpch->aggregate_on_stream); + + port += 2; + } + if (sdp) { + FILE *out = gf_fopen(sdp_name, "wt"); + fprintf(out, "%s", sdp); + gf_fclose(out); + gf_free(sdp); + } +} + +void live_session_shutdown(LiveSession *livesess) +{ + gf_seng_terminate(livesess->seng); + + if (livesess->streams) { + while (gf_list_count(livesess->streams)) { + RTPChannel *rtpch = gf_list_get(livesess->streams, 0); + gf_list_rem(livesess->streams, 0); + gf_rtp_streamer_del(rtpch->rtp); + if (rtpch->carousel_data) gf_free(rtpch->carousel_data); + gf_free(rtpch); + } + gf_list_del(livesess->streams); + } +} + + +static RTPChannel *set_broadcast_params(LiveSession *livesess, u16 esid, u32 period, u32 ts_delta, u16 aggregate_on_stream, Bool adjust_carousel_time, Bool force_rap, Bool aggregate_au, Bool discard_pending, Bool signal_rap, u32 signal_critical, Bool version_inc) +{ + RTPChannel *rtpch = NULL; + + /*locate our stream*/ + if (esid) { + u32 i=0; + while ( (rtpch = gf_list_enum(livesess->streams, &i))) { + if (rtpch->ESID == esid) break; + } + } else { + rtpch = gf_list_get(livesess->streams, 0); + } + + /*TODO - set/reset the ESID for the parsers*/ + if (!rtpch) return NULL; + + /*TODO - if discard is set, abort current carousel*/ + if (discard_pending) { + } + + /*remember RAP flag*/ + rtpch->rap = signal_rap; + rtpch->critical = signal_critical; + rtpch->m2ts_vers_inc = version_inc; + + rtpch->ts_delta = ts_delta; + rtpch->aggregate = aggregate_au; + rtpch->adjust_carousel_time = adjust_carousel_time; + + /*change stream aggregation mode*/ + if ((aggregate_on_stream != (u16)-1) && (rtpch->aggregate_on_stream != aggregate_on_stream)) { + gf_seng_enable_aggregation(livesess->seng, esid, aggregate_on_stream); + rtpch->aggregate_on_stream = aggregate_on_stream; + } + /*change stream aggregation mode*/ + if ((period!=(u32)-1) && (rtpch->carousel_period != period)) { + rtpch->carousel_period = period; + rtpch->last_carousel_time = 0; + } + + if (force_rap) { + livesess->force_carousel = 1; + } + return rtpch; +} + +int live_session(int argc, char **argv) +{ + GF_Err e; + u32 i; + char *filename = NULL; + char *dst = NULL; + char *ifce_addr = NULL; + char *sdp_name = "session.sdp"; + u16 dst_port = 7000; + u32 load_type=0; + u32 check; + u32 ttl = 1; + u32 path_mtu = 1450; + s32 next_time; + u64 last_src_modif, mod_time; + char *src_name = NULL; + Bool run, has_carousel, no_rap; + Bool udp = 0; + u16 sk_port=0; + GF_Socket *sk = NULL; + LiveSession livesess; + RTPChannel *ch; + char *update_buffer = NULL; + u32 update_buffer_size = 0; + u16 aggregate_on_stream; + Bool adjust_carousel_time, force_rap, aggregate_au, discard_pending, signal_rap, version_inc; + Bool update_context; + u32 period, ts_delta, signal_critical; + u16 es_id; + e = GF_OK; + aggregate_au = 1; + es_id = 0; + no_rap = 0; + gf_sys_init(GF_FALSE); + + memset(&livesess, 0, sizeof(LiveSession)); + + gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_INFO); + + for (i=1; i<(u32) argc; i++) { + char *arg = argv[i]; + if (arg[0] != '-') filename = arg; + else if (!strnicmp(arg, "-dst=", 5)) dst = arg+5; + else if (!strnicmp(arg, "-port=", 6)) dst_port = atoi(arg+6); + else if (!strnicmp(arg, "-sdp=", 5)) sdp_name = arg+5; + else if (!strnicmp(arg, "-mtu=", 5)) path_mtu = atoi(arg+5); + else if (!strnicmp(arg, "-ttl=", 5)) ttl = atoi(arg+5); + else if (!strnicmp(arg, "-ifce=", 6)) ifce_addr = arg+6; + else if (!strnicmp(arg, "-no-rap", 7)) no_rap = 1; + else if (!strnicmp(arg, "-dims", 5)) load_type = GF_SM_LOAD_DIMS; + else if (!strnicmp(arg, "-src=", 5)) src_name = arg+5; + else if (!strnicmp(arg, "-udp=", 5)) { + sk_port = atoi(arg+5); + udp = 1; + } + else if (!strnicmp(arg, "-tcp=", 5)) { + sk_port = atoi(arg+5); + udp = 0; + } + } + if (!filename) { + fprintf(stderr, "Missing filename\n"); + PrintLiveUsage(); + return 1; + } + + if (dst_port && dst) livesess.streams = gf_list_new(); + + livesess.seng = gf_seng_init(&livesess, filename, load_type, NULL, (load_type == GF_SM_LOAD_DIMS) ? 1 : 0); + if (!livesess.seng) { + fprintf(stderr, "Cannot create scene engine\n"); + return 1; + } + if (livesess.streams) live_session_setup(&livesess, dst, dst_port, path_mtu, ttl, ifce_addr, sdp_name); + + has_carousel = 0; + last_src_modif = src_name ? gf_file_modification_time(src_name) : 0; + + if (sk_port) { + sk = gf_sk_new(udp ? GF_SOCK_TYPE_UDP : GF_SOCK_TYPE_TCP); + if (udp) { + e = gf_sk_bind(sk, NULL, sk_port, NULL, 0, 0); + if (e != GF_OK) { + if (sk) gf_sk_del(sk); + sk = NULL; + } + } else { + } + } + + + for (i=0; i<(u32) argc; i++) { + char *arg = argv[i]; + if (!strnicmp(arg, "-rap=", 5)) { + u32 period, id, j; + RTPChannel *ch; + period = id = 0; + if (strchr(arg, ':')) { + sscanf(arg, "-rap=ESID=%u:%u", &id, &period); + e = gf_seng_enable_aggregation(livesess.seng, id, 1); + if (e) { + fprintf(stderr, "Cannot enable aggregation on stream %u: %s\n", id, gf_error_to_string(e)); + goto exit; + } + } else { + sscanf(arg, "-rap=%u", &period); + } + + j=0; + while (NULL != (ch = gf_list_enum(livesess.streams, &j))) { + if (!id || (ch->ESID==id)) + ch->carousel_period = period; + } + has_carousel = 1; + } + } + + i=0; + while (NULL != (ch = gf_list_enum(livesess.streams, &i))) { + if (ch->carousel_period) { + has_carousel = 1; + break; + } + } + + update_context = 0; + + if (has_carousel || !no_rap) { + livesess.carousel_generation = 1; + gf_seng_encode_context(livesess.seng, live_session_callback); + livesess.carousel_generation = 0; + } + + live_session_send_carousel(&livesess, NULL); + + check = 10; + run = 1; + while (run) { + check--; + if (!check) { + check = 10; + if (gf_prompt_has_input()) { + char c = gf_prompt_get_char(); + switch (c) { + case 'q': + run=0; + break; + case 'U': + livesess.critical = 1; + case 'u': + { + GF_Err e; + char szCom[8192]; + fprintf(stderr, "Enter command to send:\n"); + szCom[0] = 0; + if (1 > scanf("%[^\t\n]", szCom)) { + fprintf(stderr, "No command entered properly, aborting.\n"); + break; + } + /*stdin flush bug*/ + while (getchar()!='\n') {} + e = gf_seng_encode_from_string(livesess.seng, 0, 0, szCom, live_session_callback); + if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); + e = gf_seng_aggregate_context(livesess.seng, 0); + livesess.critical = 0; + update_context = 1; + } + break; + case 'E': + livesess.critical = 1; + case 'e': + { + GF_Err e; + char szCom[8192]; + fprintf(stderr, "Enter command to send:\n"); + szCom[0] = 0; + if (1 > scanf("%[^\t\n]", szCom)) { + printf("No command entered properly, aborting.\n"); + break; + } + /*stdin flush bug*/ + while (getchar()!='\n') {} + e = gf_seng_encode_from_string(livesess.seng, 0, 1, szCom, live_session_callback); + if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); + livesess.critical = 0; + e = gf_seng_aggregate_context(livesess.seng, 0); + + } + break; + + case 'p': + { + char rad[GF_MAX_PATH]; + fprintf(stderr, "Enter output file name - \"std\" for stderr: "); + if (1 > scanf("%s", rad)) { + fprintf(stderr, "No ouput file name entered, aborting.\n"); + break; + } + e = gf_seng_save_context(livesess.seng, !strcmp(rad, "std") ? NULL : rad); + fprintf(stderr, "Dump done (%s)\n", gf_error_to_string(e)); + } + break; + case 'F': + update_context = 1; + case 'f': + livesess.force_carousel = 1; + break; + } + e = GF_OK; + } + } + + /*process updates from file source*/ + if (src_name) { + mod_time = gf_file_modification_time(src_name); + if (mod_time != last_src_modif) { + FILE *srcf; + char flag_buf[201], *flag; + fprintf(stderr, "Update file modified - processing\n"); + last_src_modif = mod_time; + + srcf = gf_fopen(src_name, "rt"); + if (!srcf) continue; + + /*checks if we have a broadcast config*/ + if (!fgets(flag_buf, 200, srcf)) + flag_buf[0] = '\0'; + gf_fclose(srcf); + + aggregate_on_stream = (u16) -1; + adjust_carousel_time = force_rap = discard_pending = signal_rap = signal_critical = 0; + aggregate_au = version_inc = 1; + period = -1; + ts_delta = 0; + es_id = 0; + + /*find our keyword*/ + flag = strstr(flag_buf, "gpac_broadcast_config "); + if (flag) { + flag += strlen("gpac_broadcast_config "); + /*move to next word*/ + while (flag && (flag[0]==' ')) flag++; + + while (1) { + char *sep = strchr(flag, ' '); + if (sep) sep[0] = 0; + if (!strnicmp(flag, "esid=", 5)) es_id = atoi(flag+5); + else if (!strnicmp(flag, "period=", 7)) period = atoi(flag+7); + else if (!strnicmp(flag, "ts=", 3)) ts_delta = atoi(flag+3); + else if (!strnicmp(flag, "carousel=", 9)) aggregate_on_stream = atoi(flag+9); + else if (!strnicmp(flag, "restamp=", 8)) adjust_carousel_time = atoi(flag+8); + + else if (!strnicmp(flag, "discard=", 8)) discard_pending = atoi(flag+8); + else if (!strnicmp(flag, "aggregate=", 10)) aggregate_au = atoi(flag+10); + else if (!strnicmp(flag, "force_rap=", 10)) force_rap = atoi(flag+10); + else if (!strnicmp(flag, "rap=", 4)) signal_rap = atoi(flag+4); + else if (!strnicmp(flag, "critical=", 9)) signal_critical = atoi(flag+9); + else if (!strnicmp(flag, "vers_inc=", 9)) version_inc = atoi(flag+9); + if (sep) { + sep[0] = ' '; + flag = sep+1; + } else { + break; + } + } + + set_broadcast_params(&livesess, es_id, period, ts_delta, aggregate_on_stream, adjust_carousel_time, force_rap, aggregate_au, discard_pending, signal_rap, signal_critical, version_inc); + } + + e = gf_seng_encode_from_file(livesess.seng, es_id, aggregate_au ? 0 : 1, src_name, live_session_callback); + if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); + e = gf_seng_aggregate_context(livesess.seng, 0); + + update_context = no_rap ? 0 : 1; + } + } + + /*process updates from socket source*/ + if (sk) { + char buffer[2049]; + u32 bytes_read; + u32 update_length; + u32 bytes_received; + + + e = gf_sk_receive(sk, buffer, 2048, 0, &bytes_read); + if (e == GF_OK) { + u32 hdr_length = 0; + u8 cmd_type = buffer[0]; + bytes_received = 0; + switch (cmd_type) { + case 0: + { + GF_BitStream *bs = gf_bs_new(buffer, bytes_read, GF_BITSTREAM_READ); + gf_bs_read_u8(bs); + es_id = gf_bs_read_u16(bs); + aggregate_on_stream = gf_bs_read_u16(bs); + if (aggregate_on_stream==0xFFFF) aggregate_on_stream = -1; + adjust_carousel_time = gf_bs_read_int(bs, 1); + force_rap = gf_bs_read_int(bs, 1); + aggregate_au = gf_bs_read_int(bs, 1); + discard_pending = gf_bs_read_int(bs, 1); + signal_rap = gf_bs_read_int(bs, 1); + signal_critical = gf_bs_read_int(bs, 1); + version_inc = gf_bs_read_int(bs, 1); + gf_bs_read_int(bs, 1); + period = gf_bs_read_u16(bs); + if (period==0xFFFF) period = -1; + ts_delta = gf_bs_read_u16(bs); + update_length = gf_bs_read_u32(bs); + hdr_length = 12; + gf_bs_del(bs); + } + + set_broadcast_params(&livesess, es_id, period, ts_delta, aggregate_on_stream, adjust_carousel_time, force_rap, aggregate_au, discard_pending, signal_rap, signal_critical, version_inc); + break; + default: + update_length = 0; + break; + } + + if (update_buffer_size <= update_length) { + update_buffer = gf_realloc(update_buffer, update_length+1); + update_buffer_size = update_length+1; + } + if (update_length && (bytes_read>hdr_length) ) { + memcpy(update_buffer, buffer+hdr_length, bytes_read-hdr_length); + bytes_received = bytes_read-hdr_length; + } + while (bytes_received 20)) { + gf_sleep(20); + continue; + } + if (next_time) gf_sleep(next_time); + live_session_send_carousel(&livesess, ch); + } + +exit: + live_session_shutdown(&livesess); + if (update_buffer) gf_free(update_buffer); + if (sk) gf_sk_del(sk); + gf_sys_close(); + return e ? 1 : 0; +} + + +#endif /*!defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG)*/ + +#endif /*defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE)*/ + +u32 grab_live_m2ts(const char *grab_m2ts, const char *grab_ifce, const char *outName) +{ + char data[0x80000]; + u32 check = 50; + u64 nb_pck; + Bool first_run, is_rtp; + FILE *output; +#ifndef GPAC_DISABLE_STREAMING + u16 seq_num; + GF_RTPReorder *ch = NULL; +#endif + GF_Socket *sock; + GF_Err e = gf_m2ts_get_socket(grab_m2ts, grab_ifce, 0x80000, &sock); + + if (e) { + fprintf(stderr, "Cannot open %s: %s\n", grab_m2ts, gf_error_to_string(e)); + return 1; + } + output = gf_fopen(outName, "wb"); + if (!output) { + fprintf(stderr, "Cannot open %s: check path and rights\n", outName); + gf_sk_del(sock); + return 1; + } + + fprintf(stderr, "Dumping %s stream to %s - press q to abort\n", grab_m2ts, outName); + + first_run = 1; + is_rtp = 0; + while (1) { + u32 size = 0; + + check--; + if (!check) { + if (gf_prompt_has_input()) { + char c = (char) gf_prompt_get_char(); + if (c=='q') break; + } + check = 50; + } + + /*m2ts chunks by chunks*/ + e = gf_sk_receive(sock, data, 0x40000, 0, &size); + if (!size || e) { + gf_sleep(1); + continue; + } + if (first_run) { + first_run = 0; + /*FIXME: we assume only simple RTP packaging (no CSRC nor extensions)*/ + if ((data[0] != 0x47) && ((data[1] & 0x7F) == 33) ) { + is_rtp = 1; +#ifndef GPAC_DISABLE_STREAMING + ch = gf_rtp_reorderer_new(100, 500); +#endif + } + } + /*process chunk*/ + if (is_rtp) { +#ifndef GPAC_DISABLE_STREAMING + char *pck; + seq_num = ((data[2] << 8) & 0xFF00) | (data[3] & 0xFF); + gf_rtp_reorderer_add(ch, (void *) data, size, seq_num); + + pck = (char *) gf_rtp_reorderer_get(ch, &size); + if (pck) { + fwrite(pck+12, size-12, 1, output); + gf_free(pck); + } +#else + fwrite(data+12, size-12, 1, output); +#endif + } else { + fwrite(data, size, 1, output); + } + } + nb_pck = gf_ftell(output); + nb_pck /= 188; + fprintf(stderr, "Captured "LLU" TS packets\n", nb_pck ); + gf_fclose(output); + gf_sk_del(sock); + +#ifndef GPAC_DISABLE_STREAMING + if (ch) + gf_rtp_reorderer_del(ch); +#endif + return 0; +} + + + diff --git a/applications/mp4box/main.c b/applications/mp4box/main.c new file mode 100644 index 0000000..d199ccf --- /dev/null +++ b/applications/mp4box/main.c @@ -0,0 +1,4680 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2000-2012 + * All rights reserved + * + * This file is part of GPAC / mp4box application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include + +#ifndef GPAC_DISABLE_SMGR +#include +#endif + +#ifdef GPAC_DISABLE_ISOM + +#error "Cannot compile MP4Box if GPAC is not built with ISO File Format support" + +#else + +#if defined(WIN32) && !defined(_WIN32_WCE) +#include +#include +#endif + +#include + +/*RTP packetizer flags*/ +#ifndef GPAC_DISABLE_STREAMING +#include +#endif + +#ifndef GPAC_DISABLE_MCRYPT +#include +#endif + +#include + +#include + +#include + +#define BUFFSIZE 8192 + +/*in fileimport.c*/ + +#ifndef GPAC_DISABLE_MEDIA_IMPORT +void convert_file_info(char *inName, u32 trackID); +#endif + +#ifndef GPAC_DISABLE_ISOM_WRITE + +GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample); +GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, char *inName, Double interleaving_time, Double chunk_start, Bool adjust_split_end, char *outName, const char *tmpdir); +GF_Err cat_isomedia_file(GF_ISOFile *mp4, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command); + +#if !defined(GPAC_DISABLE_SCENE_ENCODER) +GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *logs); +GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *outputContext, const char *tmpdir); +#endif + +GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool make_wgt); + +#endif + +GF_Err dump_cover_art(GF_ISOFile *file, char *inName); +GF_Err dump_chapters(GF_ISOFile *file, char *inName, Bool dump_ogg); +void dump_udta(GF_ISOFile *file, char *inName, u32 dump_udta_type, u32 dump_udta_track); +GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, Bool is_box_array); +u32 id3_get_genre_tag(const char *name); + +/*in filedump.c*/ +#ifndef GPAC_DISABLE_SCENE_DUMP +GF_Err dump_file_text(char *file, char *inName, GF_SceneDumpFormat dump_mode, Bool do_log); +//void gf_check_isom_files(char *conf_rules, char *inName); +#endif +#ifndef GPAC_DISABLE_SCENE_STATS +void dump_scene_stats(char *file, char *inName, u32 stat_level); +#endif +void PrintNode(const char *name, u32 graph_type); +void PrintBuiltInNodes(u32 graph_type); + +#ifndef GPAC_DISABLE_ISOM_DUMP +void dump_isom_xml(GF_ISOFile *file, char *inName); +#endif + + +#ifndef GPAC_DISABLE_ISOM_HINTING +#ifndef GPAC_DISABLE_ISOM_DUMP +void dump_file_rtp(GF_ISOFile *file, char *inName); +#endif +void DumpSDP(GF_ISOFile *file, char *inName); +#endif + +void dump_file_timestamps(GF_ISOFile *file, char *inName); +void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName); + +#ifndef GPAC_DISABLE_ISOM_DUMP +void dump_file_ismacryp(GF_ISOFile *file, char *inName); +void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_convert, GF_TextDumpType dump_type); +#endif /*GPAC_DISABLE_ISOM_DUMP*/ + + +void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump); +void DumpMovieInfo(GF_ISOFile *file); +void PrintLanguages(); + +#ifndef GPAC_DISABLE_MPEG2TS +void dump_mpeg2_ts(char *mpeg2ts_file, char *pes_out_name, Bool prog_num); +#endif + + +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) +void PrintStreamerUsage(); +int stream_file_rtp(int argc, char **argv); +int live_session(int argc, char **argv); +void PrintLiveUsage(); +#endif + +#if !defined(GPAC_DISABLE_STREAMING) +u32 grab_live_m2ts(const char *grab_m2ts, const char *ifce_name, const char *outName); +#endif + +int mp4boxTerminal(int argc, char **argv); + +u32 quiet = 0; +Bool dvbhdemux = GF_FALSE; +Bool keep_sys_tracks = GF_FALSE; + + +/*some global vars for swf import :(*/ +u32 swf_flags = 0; +Float swf_flatten_angle = 0; +s32 laser_resolution = 0; + + +typedef struct { + u32 code; + const char *name; + const char *comment; +} itunes_tag; +static const itunes_tag itags[] = { + {GF_ISOM_ITUNE_ALBUM_ARTIST, "album_artist", "usage: album_artist=album artist"}, + {GF_ISOM_ITUNE_ALBUM, "album", "usage: album=name" }, + {GF_ISOM_ITUNE_TRACKNUMBER, "tracknum", "usage: track=x/N"}, + {GF_ISOM_ITUNE_TRACK, "track", "usage: track=name"}, + {GF_ISOM_ITUNE_ARTIST, "artist", "usage: artist=name"}, + {GF_ISOM_ITUNE_COMMENT, "comment", "usage: comment=any comment"}, + {GF_ISOM_ITUNE_COMPILATION, "compilation", "usage: compilation=yes,no"}, + {GF_ISOM_ITUNE_COMPOSER, "composer", "usage: composer=name"}, + {GF_ISOM_ITUNE_CREATED, "created", "usage: created=time"}, + {GF_ISOM_ITUNE_DISK, "disk", "usage: disk=x/N"}, + {GF_ISOM_ITUNE_TOOL, "tool", "usage: tool=name"}, + {GF_ISOM_ITUNE_GENRE, "genre", "usage: genre=name"}, + {GF_ISOM_ITUNE_NAME, "name", "usage: name=name"}, + {GF_ISOM_ITUNE_TEMPO, "tempo", "usage: tempo=integer"}, + {GF_ISOM_ITUNE_WRITER, "writer", "usage: writer=name"}, + {GF_ISOM_ITUNE_GROUP, "group", "usage: group=name"}, + {GF_ISOM_ITUNE_COVER_ART, "cover", "usage: cover=file.jpg,file.png"}, + {GF_ISOM_ITUNE_ENCODER, "encoder", "usage: encoder=name"}, + {GF_ISOM_ITUNE_GAPLESS, "gapless", "usage: gapless=yes,no"}, + {GF_ISOM_ITUNE_ALL, "all", "usage: all=NULL"}, +}; + +u32 nb_itunes_tags = sizeof(itags) / sizeof(itunes_tag); + + +void PrintVersion() +{ + fprintf(stderr, "MP4Box - GPAC version " GPAC_FULL_VERSION "\n" + "GPAC Copyright (c) Telecom ParisTech 2000-2012\n" + "GPAC Configuration: " GPAC_CONFIGURATION "\n" + "Features: %s\n", gpac_features()); +} + +void PrintGeneralUsage() +{ + fprintf(stderr, "General Options:\n" +#ifdef GPAC_MEMORY_TRACKING + " -mem-track: enables memory tracker\n" +#endif + " -strict-error exits after the first error is reported\n" + " -inter time_in_ms interleaves file data (track chunks of time_in_ms)\n" + " * Note 1: Interleaving is 0.5s by default\n" + " * Note 2: Performs drift checking accross tracks\n" + " * Note 3: a value of 0 disables interleaving\n" + " -old-inter time same as -inter but doesn't perform drift checking\n" + " -tight performs tight interleaving (sample based) of the file\n" + " * Note: reduces disk seek but increases file size\n" + " -flat stores file with all media data first, non-interleaved\n" + " -frag time_in_ms fragments file (track fragments of time_in_ms)\n" + " * Note: Always disables interleaving\n" + " -ffspace size inserts free space before moof in fragmented files\n" + " -out filename specifies output file name\n" + " * Note: By default input (MP4,3GP) file is overwritten\n" + " -tmp dirname specifies directory for temporary file creation\n" + " * Note: Default temp dir is OS-dependent\n" + " -co64 forces usage of 64-bit chunk offsets for ISOBMF files\n" + " -write-buffer SIZE specifies write buffer in bytes for ISOBMF files\n" + " -no-sys removes all MPEG-4 Systems info except IOD (profiles)\n" + " * Note: Set by default whith '-add' and '-cat'\n" + " -no-iod removes InitialObjectDescriptor from file\n" + " -isma rewrites the file as an ISMA 1.0 AV file\n" + " -ismax same as \'-isma\' and removes all clock references\n" + " -3gp rewrites as 3GPP(2) file (no more MPEG-4 Systems Info)\n" + " * Note 1: some tracks may be removed in the process\n" + " * Note 2: always on for *.3gp *.3g2 *.3gpp\n" + " -ipod rewrites the file for iPod\n" + " -psp rewrites the file for PSP devices\n" + " -brand ABCD[:v] sets major brand of file, with optional version\n" + " -ab ABCD adds given brand to file's alternate brand list\n" + " -rb ABCD removes given brand from file's alternate brand list\n" + " -cprt string adds copyright string to movie\n" + " -chap file adds chapter information contained in file\n" + " -set-track-id id1:id2 changes the id of a track from id1 to id2\n" + " -rem trackID removes track from file\n" + " -rap trackID removes all non-RAP samples from track\n" + " -enable trackID enables track\n" + " -disable trackID disables track\n" + " -new forces creation of a new destination file\n" + " -timescale VAL sets movie timescale to VAL ticks per second (default is 600).\n" + " -lang [tkID=]LAN sets track language. LAN is the BCP-47 code (eng, en-UK, ...)\n" + " -delay tkID=TIME sets track start delay in ms.\n" + " -par tkID=PAR sets visual track pixel aspect ratio (PAR=N:D or \"none\")\n" + " -name tkID=NAME sets track handler name\n" + " * NAME can indicate a UTF-8 file (\"file://file name\"\n" + " -itags tag1[:tag2] sets iTunes tags to file - more info: MP4Box -tag-list.\n" + " -split time_sec splits in files of time_sec max duration\n" + " * Note: this removes all MPEG-4 Systems media\n" + " -split-size size splits in files of max filesize kB. same as -splits.\n" + " * Note: this removes all MPEG-4 Systems media\n" + " -split-rap splits in files beginning at each RAP. same as -splitr.\n" + " * Note: this removes all MPEG-4 Systems media\n" + " -split-chunk S:E extracts a new file from Start to End (in seconds). same as -splitx\n" + " * Note: this removes all MPEG-4 Systems media\n" + " -splitz S:E same as -split-chunk, but adjust the end time to be before the last RAP sample\n" + " * Note: this removes all MPEG-4 Systems media\n" + " -group-add fmt creates a new grouping information in the file. Format is\n" + " a colon-separated list of following options:\n" + " refTrack=ID: ID of the track used as a group reference.\n" + " If not set, the track will belong to the same group as the previous trackID specified.\n" + " If 0 or no previous track specified, a new alternate group will be created\n" + " switchID=ID: ID of the switch group to create.\n" + " If 0, a new ID will be computed for you\n" + " If <0, disables SwitchGroup\n" + " criteria=string: list of space-separated 4CCs.\n" + " trackID=ID: ID of the track to add to this group.\n" + "\n" + " *WARNING* Options modify state as they are parsed:\n" + " trackID=1:criteria=lang:trackID=2\n" + " is different from:\n" + " criteria=lang:trackID=1:trackID=2\n" + "\n" + " -group-rem-track ID removes track from its group\n" + " -group-rem ID removes the track's group\n" + " -group-clean removes all group information from all tracks\n" + " -group-single puts all tracks in a single group\n" + " -ref id:XXXX:refID adds a reference of type 4CC from track ID to track refID\n" + " -keep-utc keeps UTC timing in the file after edit\n" + " -udta ID:[OPTS] sets udta for given track or movie if ID is 0. OPTS is a colon separated list of:\n" + " type=CODE where code is the 4CC code of the UDTA (not needed for box= option)\n" + " box=FILE where FILE is the location of the udta data, formatted as serialized boxes\n" + " box=base64,DATA where DATA is the base64 encoded udta data, formatted as serialized boxes\n" + " src=FILE where FILE is the location of the udta data (will be stored in a single box of type CODE)\n" + " src=base64,DATA where DATA is the base64 encoded udta data (will be stored in a single box of type CODE)\n" + " If no source is set, UDTA of type CODE will be removed\n" + "\n"); +} + +void PrintDASHUsage() +{ + fprintf(stderr, "DASH Options:\n" + " -dash dur enables DASH-ing of the file(s) with a segment duration of DUR ms\n" + " Note: the duration of a fragment (subsegment) is set\n" + " using the -frag switch.\n" + " Note: for onDemand profile, sets duration of a subsegment\n" + " -dash-live[=F] dur generates a live DASH session using dur segment duration, optionally writing live context to F\n" + " MP4Box will run the live session until \'q\' is pressed or a fatal error occurs.\n" + " -ddbg-live[=F] dur same as -dash-live without time regulation for debug purposes.\n" + " -frag time_in_ms Specifies a fragment duration of time_in_ms.\n" + " * Note: By default, this is the DASH duration\n" + " -out filename specifies output MPD file name.\n" + " -tmp dirname specifies directory for temporary file creation\n" + " * Note: Default temp dir is OS-dependent\n" + " -profile NAME specifies the target DASH profile: \"onDemand\",\n" + " \"live\", \"main\", \"simple\", \"full\",\n" + " \"hbbtv1.5:live\", \"dashavc264:live\", \"dashavc264:onDemand\"\n" + " * This will set default option values to ensure conformance to the desired profile\n" + " * Default profile is \"full\" in static mode, \"live\" in dynamic mode\n" + " -profile-ext STRING specifies a list of profile extensions, as used by DASH-IF and DVB.\n" + " The string will be colon-concatenated with the profile used\n" + "\n" + "Input media files to dash can use the following modifiers\n" + " \"#trackID=N\" only uses the track ID N from the source file\n" + " \"#video\" only uses the first video track from the source file\n" + " \"#audio\" only uses the first video track from the source file\n" + " \":id=NAME\" sets the representation ID to NAME\n" + " \":period=NAME\" sets the representation's period to NAME. Multiple periods may be used\n" + " period appear in the MPD in the same order as specified with this option\n" + " \":BaseURL=NAME\" sets the BaseURL. Set multiple times for multiple BaseURLs\n" + " \":bandwidth=VALUE\" sets the representation's bandwidth to a given value\n" + " \":duration=VALUE\" Increases the duration of this period by the given duration in seconds\n" + " only used when no input media is specified (remote period insertion), eg :period=X:xlink=Z:duration=Y.\n" + " \":xlink=VALUE\" sets the xlink value for the period containing this element\n" + " only the xlink declared on the first rep of a period will be used\n" + " \":role=VALUE\" sets the role of this representation (cf DASH spec).\n" + " media with different roles belong to different adaptation sets.\n" + " \":desc_p=VALUE\" adds a descriptor at the Period level. Value must be a properly formatted XML element.\n" + " \":desc_as=VALUE\" adds a descriptor at the AdaptationSet level. Value must be a properly formatted XML element.\n" + " two input files with different values will be in different AdaptationSet elements.\n" + " \":desc_as_c=VALUE\" adds a descriptor at the AdaptationSet level. Value must be a properly formatted XML element.\n" + " value is ignored while creating AdaptationSet elements.\n" + " \":desc_rep=VALUE\" adds a descriptor at the Representation level. Value must be a properly formatted XML element.\n" + " value is ignored while creating AdaptationSet elements.\n" + "\n" + " -rap segments begin with random access points\n" + " Note: segment duration may not be exactly what asked by\n" + " \"-dash\" since encoded video data is not modified\n" + " -frag-rap All fragments begin with random access points\n" + " Note: fragment duration may not be exactly what is asked by\n" + " \"-frag\" since encoded video data is not modified\n" + " -segment-name name sets the segment name for generated segments\n" + " If not set (default), segments are concatenated in output file\n" + " except in \"live\" profile where dash_%%s is used\n" + " -segment-ext name sets the segment extension. Default is m4s, \"null\" means no extension\n" + " -segment-timeline uses SegmentTimeline when generating segments.\n" + " -segment-marker MARK adds a box of type \'MARK\' at the end of each DASH segment. MARK shall be a 4CC identifier\n" + " -insert-utc inserts UTC clock at the begining of each ISOBMF segment\n" + " -base-url string sets Base url at MPD level. Can be used several times.\n" + " -mpd-title string sets MPD title.\n" + " -mpd-source string sets MPD source.\n" + " -mpd-info-url string sets MPD info url.\n" + " -cprt string adds copyright string to MPD\n" + " -dash-ctx FILE stores/restore DASH timing from FILE.\n" + " -dynamic uses dynamic MPD type instead of static.\n" + " -last-dynamic same as dynamic but closes the period (insert lmsg brand if needed and update duration).\n" + " -mpd-duration DUR sets the duration in second of a live session (0 by default). If 0, you must use -mpd-refresh.\n" + " -mpd-refresh TIME specifies MPD update time in seconds (double can be used).\n" + " -time-shift TIME specifies MPD time shift buffer depth in seconds (default 0). Specify -1 to keep all files\n" + " -subdur DUR specifies maximum duration in ms of the input file to be dashed in LIVE or context mode.\n" + " NOTE: This does not change the segment duration: dashing stops once segments produced exceeded the duration.\n" + " -min-buffer TIME specifies MPD min buffer time in milliseconds\n" + " -ast-offset TIME specifies MPD AvailabilityStartTime offset in ms if positive, or availabilityTimeOffset of each representation if negative. Default is 0 sec delay\n" + " -dash-scale SCALE specifies that timing for -dash and -frag are expressed in SCALE units per seconds\n" + " -mem-frags fragments will be produced in memory rather than on disk before flushing to disk\n" + " -pssh-moof stores PSSH boxes in first moof of each segments. By default PSSH are stored in movie box.\n" + " -sample-groups-traf stores sample group descriptions in traf (duplicated for each traf) rather than in moof. By default sample group descriptions are stored in movie box.\n" + + "\n" + "Advanced Options, should not be needed when using -profile:\n" + " -subsegs-per-sidx N sets the number of subsegments to be written in each SIDX box\n" + " If 0, a single SIDX box is used per segment\n" + " If -1, no SIDX box is used\n" + " -url-template uses SegmentTemplate instead of explicit sources in segments.\n" + " Ignored if segments are stored in the output file.\n" + " -daisy-chain uses daisy-chain SIDX instead of hierarchical. Ignored if frags/sidx is 0.\n" + " -single-segment uses a single segment for the whole file (OnDemand profile). \n" + " -single-file uses a single file for the whole file (default). \n" + " -bs-switching MODE sets bitstream switching to \"inband\" (default), \"merge\", \"multi\", \"no\" or \"single\" to test with single input.\n" + " -moof-sn N sets sequence number of first moof to N\n" + " -tfdt N sets TFDT of first traf to N in SCALE units (cf -dash-scale)\n" + " -no-frags-default disables default flags in fragments\n" + " -single-traf uses a single track fragment per moof (smooth streaming and derived specs may require this)\n" + " -dash-ts-prog N program_number to be considered in case of an MPTS input file.\n" + " -frag-rt when using fragments in live mode, flush fragments according to their timing (only supported with a single input).\n" + "\n"); +} + +void PrintFormats() +{ + fprintf(stderr, "Supported raw formats and file extensions:\n" + " NHNT .media .nhnt .info\n" + " NHML .nhml (opt: .media .info)\n" + " MPEG-1-2 Video .m1v .m2v\n" + " MPEG-4 Video .cmp .m4v\n" + " H263 Video .263 .h263\n" + " AVC/H264 Video .h264 .h26L .264 .26L .x264 .svc\n" + " HEVC Video .hevc .h265 .265 .hvc .shvc\n" + " JPEG Images .jpg .jpeg\n" + " PNG Images .png\n" + " MPEG 1-2 Audio .mp3, .m1a, .m2a\n" + " ADTS-AAC Audio .aac\n" + " AMR(WB) Audio .amr .awb\n" + " EVRC Audio .evc\n" + " SMV Audio .smv\n" + "\n" + "Supported containers and file extensions:\n" + " AVI .avi\n" + " MPEG-2 PS .mpg .mpeg .vob .vcd .svcd\n" + " MPEG-2 TS .ts .m2t\n" + " QCP .qcp\n" + " OGG .ogg\n" + " ISO-Media files no extension checking\n" + "\n" + "Supported text formats:\n" + " SRT Subtitles .srt\n" + " SUB Subtitles .sub\n" + " GPAC Timed Text .ttxt\n" + " QuickTime TeXML Text .xml (cf QT documentation)\n" + "\n" + "Supported Scene formats:\n" + " MPEG-4 XMT-A .xmt .xmta .xmt.gz .xmta.gz\n" + " MPEG-4 BT .bt .bt.gz\n" + " VRML .wrl .wrl.gz\n" + " X3D-XML .x3d .x3d.gz\n" + " X3D-VRML .x3dv .x3dv.gz\n" + " MacroMedia Flash .swf (very limited import support only)\n" + "\n" + ); +} + +void PrintImportUsage() +{ + fprintf(stderr, "Importing Options\n" + "\nFile importing syntax:\n" + " \"#video\" \"#audio\" base import for most AV files\n" + " \"#trackID=ID\" track import for IsoMedia and other files\n" + " \"#pid=ID\" stream import from MPEG-2 TS\n" + " \":dur=D\" imports only the first D seconds\n" + " \":lang=LAN\" sets imported media language code\n" + " \":delay=delay_ms\" sets imported media initial delay in ms\n" + " \":par=PAR\" sets visual pixel aspect ratio (PAR=Num:Den)\n" + " \":name=NAME\" sets track handler name\n" + " \":ext=EXT\" overrides file extension when importing\n" + " \":hdlr=code\" sets track handler type to the given code point (4CC)\n" + " \":disable\" imported track(s) will be disabled\n" + " \":group=G\" adds the track as part of the G alternate group.\n" + " If G is 0, the first available GroupID will be picked.\n" + " \":fps=VAL\" same as -fps option\n" + " \":rap\" imports only RAP samples\n" + " \":trailing\" keeps trailing 0-bytes in AVC/HEVC samples\n" + " \":agg=VAL\" same as -agg option\n" + " \":dref\" same as -dref option\n" + " \":nodrop\" same as -nodrop option\n" + " \":packed\" same as -packed option\n" + " \":sbr\" same as -sbr option\n" + " \":sbrx\" same as -sbrx option\n" + " \":ovsbr\" same as -ovsbr option\n" + " \":ps\" same as -ps option\n" + " \":psx\" same as -psx option\n" + " \":mpeg4\" same as -mpeg4 option\n" + " \":svc\" import SVC/SHVC with explicit signaling (no AVC base compatibility)\n" + " \":nosvc\" discard SVC/SHVC data when importing\n" + " \":svcmode=MODE\" sets SVC/SHVC import mode:\n" + " \" split : each layer is in its own track\n" + " \" merge : all layers are merged in a single track\n" + " \" splitbase : all layers are merged in a track, and the AVC base in another\n" + " \" splitnox : each layer is in its own track, and no extractors are written\n" + " \":subsamples\" adds SubSample information for AVC+SVC\n" + " \":forcesync\" forces non IDR samples with I slices to be marked as sync points (AVC GDR)\n" + " !! RESULTING FILE IS NOT COMPLIANT WITH THE SPEC but will fix seeking in most players\n" + " \":xps_inband\" Sets xPS inband for AVC/H264 and HEVC (for reverse operation, re-import from raw media)\n" + " \":negctts\" uses negative CTS-DTS offsets (ISO4 brand)\n" + " \":stype=4CC\" forces the sample description type to a different value\n" + " !! THIS MAY BREAK THE FILE WRITING !!\n" + " \":chap\" specifies the track is a chapter track\n" + " \":chapter=NAME\" adds a single chapter (old nero format) with given name lasting the entire file\n" + " This command can be used in -cat as well\n" + " \":chapfile=file\" adds a chapter file (old nero format)\n" + " This command can be used in -cat as well\n" + " \":layout=WxHxXxY\" specifies the track layout\n" + " - if W (resp H) = 0, the max width (resp height) of\n" + " the tracks in the file are used.\n" + " - if Y=-1, the layout is moved to the bottom of the\n" + " track area\n" + " - X and Y can be omitted (:layout=WxH)\n" + " \":rescale=TS\" forces media timescale to TS !! changes the media duration\n" + " \":timescale=TS\" sets import timescale to TS\n" + " \":noedit\" do not set edit list when importing B-frames video tracks\n" + " \":rvc=FILENAME\" sets TVC configuration for the media\n" + " \":fmt=FORMAT\" overrides format detection with given format (cf BT/XMTA doc)\n" + " \":profile=INT\" overrides AVC profile\n" + " \":level=INT\" overrides AVC level\n" + + " \":font=name\" specifies font name for text import (default \"Serif\")\n" + " \":size=s\" specifies font size for text import (default 18)\n" + " \":text_layout=WxHxXxY\" specifies the track text layout\n" + " - if W (resp H) = 0, the max width (resp height) of\n" + " the tracks in the file are used.\n" + " - if Y=-1, the layout is moved to the bottom of the\n" + " track area\n" + " - X and Y can be omitted (:layout=WxH)\n" + + " \":swf-global\" all SWF defines are placed in first scene replace\n" + " * Note: By default SWF defines are sent when needed\n" + " \":swf-no-ctrl\" uses a single stream for movie control and dictionary\n" + " * Note: this will disable ActionScript\n" + " \":swf-no-text\" removes all SWF text\n" + " \":swf-no-font\" removes all embedded SWF Fonts (terminal fonts used)\n" + " \":swf-no-line\" removes all lines from SWF shapes\n" + " \":swf-no-grad\" removes all gradients from swf shapes\n" + " \":swf-quad\" uses quadratic bezier curves instead of cubic ones\n" + " \":swf-xlp\" support for lines transparency and scalability\n" + " \":swf-ic2d\" uses indexed curve 2D hardcoded proto\n" + " \":swf-same-app\" appearance nodes are reused\n" + " \":swf-flatten=ang\" complementary angle below which 2 lines are merged\n" + " * Note: angle \'0\' means no flattening\n" + " \":kind=SCHEMA:type\" sets kind for the track\n" + " \":txtflags=flags\" sets display flags (hexa number) of text track\n" + " \":txtflags+=flags\" adds display flags (hexa number) to text track\n" + " \":txtflags-=flags\" removes display flags (hexa number) from text track\n" + "\n" + " -add file add file tracks to (new) output file\n" + " -cat file concatenates file samples to (new) output file\n" + " * Note: creates tracks if needed\n" + " * Note: aligns initial timestamp of the file to be concatenated.\n" + " -catx file same as cat but new tracks can be imported before concatenation by specifying '+ADD_COMMAND'\n" + " where ADD_COMMAND is a regular -add syntax\n" + " -unalign-cat does not attempt to align timestamps of samples inbetween tracks\n" + " -force-cat skips media configuration check when concatenating file\n" + " !!! THIS MAY BREAK THE CONCATENATED TRACK(S) !!!\n" + " -keep-sys keeps all MPEG-4 Systems info when using '-add' / 'cat'\n" + " -keep-all keeps all existing tracks when using '-add'\n" + " * Note: only used when adding IsoMedia files\n" + "\n" + "All the following options can be specified as default or for each track.\n" + "When specified by track the syntax is \":opt\" or \":opt=val\".\n\n" + " -dref keeps media data in original file\n" + " -no-drop forces constant FPS when importing AVI video\n" + " -packed forces packed bitstream when importing raw ASP\n" + " -sbr backward compatible signaling of AAC-SBR\n" + " -sbrx non-backward compatible signaling of AAC-SBR\n" + " -ps backward compatible signaling of AAC-PS\n" + " -psx non-backward compatible signaling of AAC-PS\n" + " -ovsbr oversample SBR\n" + " * Note: SBR AAC, PS AAC and oversampled SBR cannot be detected at import time\n" + " -fps FPS forces frame rate for video and SUB subtitles import\n" + " FPS is either a number or expressed as timescale-increment\n" + " * For raw H263 import, default FPS is 15\n" + " * For all other imports, default FPS is 25\n" + " !! THIS IS IGNORED FOR IsoMedia IMPORT !!\n" + " -mpeg4 forces MPEG-4 sample descriptions when possible (3GPP2)\n" + " For AAC, forces MPEG-4 AAC signaling even if MPEG-2\n" + " -agg N aggregates N audio frames in 1 sample (3GP media only)\n" + " * Note: Maximum value is 15 - Disabled by default\n" + "\n" + ); +} + +void PrintEncodeUsage() +{ + fprintf(stderr, "MPEG-4 Scene Encoding Options\n" + " -mp4 specify input file is for encoding.\n" + " -def encode DEF names\n" + " -sync time_in_ms forces BIFS sync sample generation every time_in_ms\n" + " * Note: cannot be used with -shadow\n" + " -shadow time_ms forces BIFS sync shadow sample generation every time_ms.\n" + " * Note: cannot be used with -sync\n" + " -log generates scene codec log file if available\n" + " -ms file specifies file for track importing\n" + "\nChunk Processing\n" + " -ctx-in file specifies initial context (MP4/BT/XMT)\n" + " * Note: input file must be a commands-only file\n" + " -ctx-out file specifies storage of updated context (MP4/BT/XMT)\n" + "\n" + "LASeR Encoding options\n" + " -resolution res resolution factor (-8 to 7, default 0)\n" + " all coords are multiplied by 2^res before truncation\n" + " -coord-bits bits bits used for encoding truncated coordinates\n" + " (0 to 31, default 12)\n" + " -scale-bits bits extra bits used for encoding truncated scales\n" + " (0 to 4, default 0)\n" + " -auto-quant res resolution is given as if using -resolution\n" + " but coord-bits and scale-bits are infered\n" + ); +} + +void PrintEncryptUsage() +{ + fprintf(stderr, "ISMA Encryption/Decryption Options\n" + " -crypt drm_file crypts a specific track using ISMA AES CTR 128\n" + " -decrypt [drm_file] decrypts a specific track using ISMA AES CTR 128\n" + " * Note: drm_file can be omitted if keys are in file\n" + " -set-kms kms_uri changes KMS location for all tracks or a given one.\n" + " * to address a track, use \'tkID=kms_uri\'\n" + "\n" + "DRM file syntax for GPAC ISMACryp:\n" + " File is XML and shall start with xml header\n" + " File root is an \"ISMACryp\" element\n" + " File is a list of \"cryptrack\" elements\n" + "\n" + "cryptrack attributes are\n" + " TrackID ID of track to en/decrypt\n" + " key AES-128 key formatted (hex string \'0x\'+32 chars)\n" + " salt CTR IV salt key (64 bits) (hex string \'0x\'+16 chars)\n" + "\nEncryption only attributes:\n" + " Scheme_URI URI of scheme used\n" + " KMS_URI URI of key management system\n" + " * Note: \'self\' writes key and salt in the file\n" + " selectiveType selective encryption type - understood values are:\n" + " \"None\" all samples encrypted (default)\n" + " \"RAP\" only encrypts random access units\n" + " \"Non-RAP\" only encrypts non-random access units\n" + " \"Rand\" random selection is performed\n" + " \"X\" Encrypts every first sample out of X (uint)\n" + " \"RandX\" Encrypts one random sample out of X (uint)\n" + "\n" + " ipmpType IPMP Signaling Type: None, IPMP, IPMPX\n" + " ipmpDescriptorID IPMP_Descriptor ID to use if IPMP(X) is used\n" + " * If not set MP4Box will generate one for you\n" + "\n" + ); +} + +void PrintHintUsage() +{ + fprintf(stderr, "Hinting Options\n" + " -hint hints the file for RTP/RTSP\n" + " -mtu size specifies RTP MTU (max size) in bytes. Default size is 1450\n" + " * Note: this includes the RTP header (12 bytes)\n" + " -copy copies media data to hint track rather than reference\n" + " * Note: speeds up server but takes much more space\n" + " -multi [maxptime] enables frame concatenation in RTP packets if possible\n" + " maxptime max packet duration in ms (optional, default 100ms)\n" + " -rate ck_rate specifies rtp rate in Hz when no default for payload\n" + " * Note: default value is 90000 (MPEG rtp rates)\n" + " -mpeg4 forces MPEG-4 generic payload whenever possible\n" + " -latm forces MPG4-LATM transport for AAC streams\n" + " -static enables static RTP payload IDs whenever possible\n" + " * By default, dynamic payloads are always used\n" + "\n" + "MPEG-4 Generic Payload Options\n" + " -ocr forces all streams to be synchronized\n" + " * Most RTSP servers only support synchronized streams\n" + " -rap signals random access points in RTP packets\n" + " -ts signals AU Time Stamps in RTP packets\n" + " -size signals AU size in RTP packets\n" + " -idx signals AU sequence numbers in RTP packets\n" + " -iod prevents systems tracks embedding in IOD\n" + " * Note: shouldn't be used with -isma option\n" + "\n" + " -add-sdp string adds sdp string to (hint) track (\"-add-sdp tkID:string\")\n" + " or movie. This will take care of SDP lines ordering\n" + " -unhint removes all hinting information.\n" + "\n"); +} +void PrintExtractUsage() +{ + fprintf(stderr, "Extracting Options:\n" + " -raw TrackID extracts track in raw format when supported\n" + " :output=FileName sets the output filename for this extraction \n" + " -raws TrackID extract each track sample to a file\n" + " * Note: \"TrackID:N\" extracts Nth sample\n" + " -nhnt TrackID extracts track in nhnt format\n" + " -nhml TrackID extracts track in nhml format (XML nhnt).\n" + " * Note: \"-nhml TrackID:full\" for full dump\n" + " -webvtt-raw TrackID extracts raw media track in WebVTT as metadata.\n" + " * Note: \"-webvtt-raw TrackID:embedded\" to include media data in the WebVTT file\n" + " -six TrackID extracts raw media track in experimental XML streaming instructions.\n" + " -single TrackID extracts track to a new mp4 file\n" + " -avi TrackID extracts visual track to an avi file\n" + " -qcp TrackID same as \'-raw\' but defaults to QCP file for EVRC/SMV\n" + " -aviraw TK extracts AVI track in raw format\n" + " $TK can be one of \"video\" \"audio\" \"audioN\"\n" + " -saf remux file to SAF multiplex\n" + " -dvbhdemux demux DVB-H file into IP Datagrams\n" + " * Note: can be used when encoding scene descriptions\n" + " -raw-layer ID same as -raw but skips SVC/MVC extractors when extracting\n" + " -diod extracts file IOD in raw format when supported\n" + "\n" +#if !defined(GPAC_DISABLE_STREAMING) + " -grab-ts IP:port grabs TS over UDP or RTP at IP:port location to output TS file\n" + " -ifce IFCE indicates default ifce for grab operations\n" +#endif + "\n"); +} +void PrintDumpUsage() +{ + fprintf(stderr, "Dumping Options\n" + " -stdb dumps/write to stdout and assumes stdout is opened in binary mode\n" + " -std dumps/write to stdout and try to reopen stdout in binary mode.\n" + " -info [trackID] prints movie info / track info if trackID specified\n" + " * Note: for non IsoMedia files, gets import options\n" + " -bt scene to bt format - removes unknown MPEG4 nodes\n" + " -xmt scene to XMT-A format - removes unknown MPEG4 nodes\n" + " -wrl scene VRML format - removes unknown VRML nodes\n" + " -x3d scene to X3D/XML format - removes unknown X3D nodes\n" + " -x3dv scene to X3D/VRML format - removes unknown X3D nodes\n" + " -lsr scene to LASeR format\n" + " -diso scene IsoMedia file boxes in XML output\n" + " -drtp rtp hint samples structure to XML output\n" + " -dts prints sample timing to text output\n" + " -dnal trackID prints NAL sample info of given track\n" + " -sdp dumps SDP description of hinted file\n" + " -dcr ISMACryp samples structure to XML output\n" + " -dump-cover Extracts cover art\n" + " -dump-chap Extracts chapter file\n" + " -dump-udta [ID:]4cc Extracts udta for the given 4CC. If ID is given, dumps from UDTA of the given track ID, otherwise moov is used.\n" + "\n" +#ifndef GPAC_DISABLE_ISOM_WRITE + " -ttxt Converts input subtitle to GPAC TTXT format\n" +#endif + " -ttxt TrackID Dumps Text track to GPAC TTXT format\n" +#ifndef GPAC_DISABLE_ISOM_WRITE + " -srt Converts input subtitle to SRT format\n" +#endif + " -srt TrackID Dumps Text track to SRT format\n" + "\n" + " -stat generates node/field statistics for scene\n" + " -stats generates node/field statistics per MPEG-4 Access Unit\n" + " -statx generates node/field statistics for scene after each AU\n" + "\n" + " -hash generates SHA-1 Hash of the input file\n" + " -bin converts input XML file using NHML bitstream syntax to binary\n" + "\n"); +} + +void PrintMetaUsage() +{ + fprintf(stderr, "Meta handling Options\n" + " -set-meta args sets given meta type - syntax: \"ABCD[:tk=ID]\"\n" + " * ABCD: four char meta type (NULL or 0 to remove meta)\n" + " * [:tk=ID]: if not set use root (file) meta\n" + " if ID is 0 use moov meta\n" + " if ID is not 0 use track meta\n" + " -add-item args adds resource to meta\n" + " * syntax: file_path + options (\':\' separated):\n" + " tk=ID: meta addressing (file, moov, track)\n" + " name=str: item name\n" + " mime=mtype: item mime type\n" + " encoding=enctype: item content-encoding type\n" + " id=id: item ID\n" + " * file_path \"this\" or \"self\": item is the file itself\n" + " -rem-item args removes resource from meta - syntax: item_ID[:tk=ID]\n" + " -set-primary args sets item as primary for meta - syntax: item_ID[:tk=ID]\n" + " -set-xml args sets meta XML data\n" + " * syntax: xml_file_path[:tk=ID][:binary]\n" + " -rem-xml [tk=ID] removes meta XML data\n" + " -dump-xml args dumps meta XML to file - syntax file_path[:tk=ID]\n" + " -dump-item args dumps item to file - syntax item_ID[:tk=ID][:path=fileName]\n" + " -package packages input XML file into an ISO container\n" + " * all media referenced except hyperlinks are added to file\n" + " -mgt packages input XML file into an MPEG-U widget with ISO container.\n" + " * all files contained in the current folder are added to the widget package\n" + "\n"); +} + +void PrintSWFUsage() +{ + fprintf(stderr, + "SWF Importer Options\n" + "\n" + "MP4Box can import simple Macromedia Flash files (\".SWF\")\n" + "You can specify a SWF input file with \'-bt\', \'-xmt\' and \'-mp4\' options\n" + "\n" + " -global all SWF defines are placed in first scene replace\n" + " * Note: By default SWF defines are sent when needed\n" + " -no-ctrl uses a single stream for movie control and dictionary\n" + " * Note: this will disable ActionScript\n" + " -no-text removes all SWF text\n" + " -no-font removes all embedded SWF Fonts (terminal fonts used)\n" + " -no-line removes all lines from SWF shapes\n" + " -no-grad removes all gradients from swf shapes\n" + " -quad uses quadratic bezier curves instead of cubic ones\n" + " -xlp support for lines transparency and scalability\n" + " -flatten ang complementary angle below which 2 lines are merged\n" + " * Note: angle \'0\' means no flattening\n" + "\n" + ); +} + +void PrintUsage() +{ + fprintf (stderr, "MP4Box [option] input [option]\n" + " -h general general options help\n" + " -h hint hinting options help\n" + " -h dash DASH segmenter help\n" + " -h import import options help\n" + " -h encode encode options help\n" + " -h meta meta handling options help\n" + " -h extract extraction options help\n" + " -h dump dump options help\n" + " -h swf Flash (SWF) options help\n" + " -h crypt ISMA E&A options help\n" + " -h format supported formats help\n" + " -h rtp file streamer help\n" + " -h live BIFS streamer help\n" + " -h all all options are printed\n" + "\n" + " -nodes lists supported MPEG4 nodes\n" + " -node NodeName gets MPEG4 node syntax and QP info\n" + " -xnodes lists supported X3D nodes\n" + " -xnode NodeName gets X3D node syntax\n" + " -snodes lists supported SVG nodes\n" + " -snode NodeName gets SVG node syntax\n" + " -languages lists supported ISO 639 languages\n" + "\n" + " -quiet quiet mode\n" + " -noprog disables progress\n" + " -v verbose mode\n" + " -logs set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" + " -version gets build version\n" + " -- INPUT escape option if INPUT starts with - character\n" + "\n" + ); +} + + +void scene_coding_log(void *cbk, u32 log_level, u32 log_tool, const char *fmt, va_list vlist) +{ + FILE *logs = cbk; + if (log_tool != GF_LOG_CODING) return; + vfprintf(logs, fmt, vlist); + fflush(logs); +} + +#ifndef GPAC_DISABLE_ISOM_HINTING + +/* + MP4 File Hinting +*/ + +void SetupClockReferences(GF_ISOFile *file) +{ + u32 i, count, ocr_id; + count = gf_isom_get_track_count(file); + if (count==1) return; + ocr_id = 0; + for (i=0; iOCRESID = ocr_id; + gf_isom_change_mpeg4_description(file, i+1, 1, esd); + gf_odf_desc_del((GF_Descriptor *) esd); + } + } +} + +/*base RTP payload type used (you can specify your own types if needed)*/ +#define BASE_PAYT 96 + +GF_Err HintFile(GF_ISOFile *file, u32 MTUSize, u32 max_ptime, u32 rtp_rate, u32 base_flags, Bool copy_data, Bool interleave, Bool regular_iod, Bool single_group) +{ + GF_ESD *esd; + GF_InitialObjectDescriptor *iod; + u32 i, val, res, streamType; + u32 sl_mode, prev_ocr, single_ocr, nb_done, tot_bw, bw, flags, spec_type; + GF_Err e; + char szPayload[30]; + GF_RTPHinter *hinter; + Bool copy, has_iod, single_av; + u8 init_payt = BASE_PAYT; + u32 iod_mode, mtype; + u32 media_group = 0; + u8 media_prio = 0; + + tot_bw = 0; + prev_ocr = 0; + single_ocr = 1; + + has_iod = 1; + iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file); + if (!iod) has_iod = 0; + else { + if (!gf_list_count(iod->ESDescriptors)) has_iod = 0; + gf_odf_desc_del((GF_Descriptor *) iod); + } + + spec_type = gf_isom_guess_specification(file); + single_av = single_group ? 1 : gf_isom_is_single_av(file); + + /*first make sure we use a systems track as base OCR*/ + for (i=0; idecoderConfig->streamType; + if (!prev_ocr) { + prev_ocr = esd->OCRESID; + if (!esd->OCRESID) prev_ocr = esd->ESID; + } else if (esd->OCRESID && prev_ocr != esd->OCRESID) { + single_ocr = 0; + } + /*OD MUST BE WITHOUT REFERENCES*/ + if (streamType==1) copy = 1; + } + gf_odf_desc_del((GF_Descriptor *) esd); + + if (!regular_iod && gf_isom_is_track_in_root_od(file, i+1)) { + /*single AU - check if base64 would fit in ESD (consider 33% overhead of base64), otherwise stream*/ + if (gf_isom_get_sample_count(file, i+1)==1) { + GF_ISOSample *samp = gf_isom_get_sample(file, i+1, 1, &val); + if (streamType) { + res = gf_hinter_can_embbed_data(samp->data, samp->dataLength, streamType); + } else { + /*not a system track, we shall hint it*/ + res = 0; + } + if (samp) gf_isom_sample_del(&samp); + if (res) continue; + } + } + if (interleave) sl_mode |= GP_RTP_PCK_USE_INTERLEAVING; + + hinter = gf_hinter_track_new(file, i+1, MTUSize, max_ptime, rtp_rate, sl_mode, init_payt, copy, media_group, media_prio, &e); + + if (!hinter) { + if (e) { + fprintf(stderr, "Cannot create hinter (%s)\n", gf_error_to_string(e)); + if (!nb_done) return e; + } + continue; + } + bw = gf_hinter_track_get_bandwidth(hinter); + tot_bw += bw; + flags = gf_hinter_track_get_flags(hinter); + + //set extraction mode for AVC/SVC + gf_isom_set_nalu_extract_mode(file, i+1, GF_ISOM_NALU_EXTRACT_LAYER_ONLY); + + gf_hinter_track_get_payload_name(hinter, szPayload); + fprintf(stderr, "Hinting track ID %d - Type \"%s:%s\" (%s) - BW %d kbps\n", gf_isom_get_track_id(file, i+1), gf_4cc_to_str(mtype), gf_4cc_to_str(mtype), szPayload, bw); + if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) fprintf(stderr, "\tMPEG-4 Systems stream carousel enabled\n"); + /* + if (flags & GP_RTP_PCK_FORCE_MPEG4) fprintf(stderr, "\tMPEG4 transport forced\n"); + if (flags & GP_RTP_PCK_USE_MULTI) fprintf(stderr, "\tRTP aggregation enabled\n"); + */ + e = gf_hinter_track_process(hinter); + + if (!e) e = gf_hinter_track_finalize(hinter, has_iod); + gf_hinter_track_del(hinter); + + if (e) { + fprintf(stderr, "Error while hinting (%s)\n", gf_error_to_string(e)); + if (!nb_done) return e; + } + init_payt++; + nb_done ++; + } + + if (has_iod) { + iod_mode = GF_SDP_IOD_ISMA; + if (regular_iod) iod_mode = GF_SDP_IOD_REGULAR; + } else { + iod_mode = GF_SDP_IOD_NONE; + } + gf_hinter_finalize(file, iod_mode, tot_bw); + + if (!single_ocr) + fprintf(stderr, "Warning: at least 2 timelines found in the file\nThis may not be supported by servers/players\n\n"); + + return GF_OK; +} + +#endif /*GPAC_DISABLE_ISOM_HINTING*/ + +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_AV_PARSERS) + +static void check_media_profile(GF_ISOFile *file, u32 track) +{ + u8 PL; + GF_M4ADecSpecInfo dsi; + GF_ESD *esd = gf_isom_get_esd(file, track, 1); + if (!esd) return; + + switch (esd->decoderConfig->streamType) { + case 0x04: + PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_VISUAL); + if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_MPEG4_PART2) { + GF_M4VDecSpecInfo dsi; + gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); + if (dsi.VideoPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, dsi.VideoPL); + } else if ((esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) || (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_SVC)) { + gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0x15); + } else if (!PL) { + gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0xFE); + } + break; + case 0x05: + PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_AUDIO); + switch (esd->decoderConfig->objectTypeIndication) { + case GPAC_OTI_AUDIO_AAC_MPEG2_MP: + case GPAC_OTI_AUDIO_AAC_MPEG2_LCP: + case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP: + case GPAC_OTI_AUDIO_AAC_MPEG4: + gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); + if (dsi.audioPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, dsi.audioPL); + break; + default: + if (!PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0xFE); + } + break; + } + gf_odf_desc_del((GF_Descriptor *) esd); +} +void remove_systems_tracks(GF_ISOFile *file) +{ + u32 i, count; + + count = gf_isom_get_track_count(file); + if (count==1) return; + + /*force PL rewrite*/ + gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0); + gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0); + gf_isom_set_pl_indication(file, GF_ISOM_PL_OD, 1); /*the lib always remove IOD when no profiles are specified..*/ + + for (i=0; iact_type = act_type; + meta->mime_type[0] = 0; + meta->enc_type[0] = 0; + meta->szName[0] = 0; + meta->szPath[0] = 0; + meta->trackID = 0; + meta->root_meta = 1; + + if (!opts) return 0; + while (1) { + if (!opts || !opts[0]) return ret; + if (opts[0]==':') opts += 1; + strcpy(szSlot, opts); + next = strchr(szSlot, ':'); + /*use ':' as separator, but beware DOS paths...*/ + if (next && next[1]=='\\') next = strchr(szSlot+2, ':'); + if (next) next[0] = 0; + + if (!strnicmp(szSlot, "tk=", 3)) { + sscanf(szSlot, "tk=%u", &meta->trackID); + meta->root_meta = 0; + ret = 1; + } + else if (!strnicmp(szSlot, "id=", 3)) { + meta->item_id = atoi(szSlot+3); + ret = 1; + } + else if (!strnicmp(szSlot, "name=", 5)) { + strcpy(meta->szName, szSlot+5); + ret = 1; + } + else if (!strnicmp(szSlot, "path=", 5)) { + strcpy(meta->szPath, szSlot+5); + ret = 1; + } + else if (!strnicmp(szSlot, "mime=", 5)) { + strcpy(meta->mime_type, szSlot+5); + ret = 1; + } + else if (!strnicmp(szSlot, "encoding=", 9)) { + strcpy(meta->enc_type, szSlot+9); + ret = 1; + } + else if (!strnicmp(szSlot, "dref", 4)) { + meta->use_dref = 1; + ret = 1; + } + else if (!stricmp(szSlot, "binary")) { + if (meta->act_type==META_ACTION_SET_XML) meta->act_type=META_ACTION_SET_BINARY_XML; + ret = 1; + } + else if (!strchr(szSlot, '=')) { + switch (meta->act_type) { + case META_ACTION_SET_TYPE: + if (!stricmp(szSlot, "null") || !stricmp(szSlot, "0")) meta->meta_4cc = 0; + else meta->meta_4cc = GF_4CC(szSlot[0], szSlot[1], szSlot[2], szSlot[3]); + ret = 1; + break; + case META_ACTION_ADD_ITEM: + case META_ACTION_SET_XML: + case META_ACTION_DUMP_ITEM: + strcpy(meta->szPath, szSlot); + ret = 1; + break; + case META_ACTION_REM_ITEM: + case META_ACTION_SET_PRIMARY_ITEM: + case META_ACTION_DUMP_XML: + meta->item_id = atoi(szSlot); + ret = 1; + break; + default: + break; + } + } + opts += strlen(szSlot); + } + return ret; +} +#endif + + +typedef enum { + TSEL_ACTION_SET_PARAM = 0, + TSEL_ACTION_REMOVE_TSEL = 1, + TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP = 2, + TSEL_ACTION_REMOVE_ALL_TSEL_IN_FILE = 3, +} TSELActionType; + +typedef struct +{ + TSELActionType act_type; + u32 trackID; + + u32 refTrackID; + u32 criteria[30]; + u32 nb_criteria; + Bool is_switchGroup; + u32 switchGroupID; +} TSELAction; + +static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_act, TSELActionType act) +{ + u32 refTrackID = 0; + Bool has_switch_id; + u32 switch_id = 0; + u32 criteria[30]; + u32 nb_criteria = 0; + TSELAction *tsel_act; + char szSlot[1024], *next; + TSELAction *tsel_list = *__tsel_list; + + has_switch_id = 0; + + + if (!opts) return 0; + while (1) { + if (!opts || !opts[0]) return 1; + if (opts[0]==':') opts += 1; + strcpy(szSlot, opts); + next = strchr(szSlot, ':'); + /*use ':' as separator, but beware DOS paths...*/ + if (next && next[1]=='\\') next = strchr(szSlot+2, ':'); + if (next) next[0] = 0; + + + if (!strnicmp(szSlot, "ref=", 4)) refTrackID = atoi(szSlot+4); + else if (!strnicmp(szSlot, "switchID=", 9)) { + if (atoi(szSlot+9)<0) { + switch_id = 0; + has_switch_id = 0; + } else { + switch_id = atoi(szSlot+9); + has_switch_id = 1; + } + } + else if (!strnicmp(szSlot, "switchID", 8)) { + switch_id = 0; + has_switch_id = 1; + } + else if (!strnicmp(szSlot, "criteria=", 9)) { + u32 j=9; + nb_criteria = 0; + while (j+3nb_baseURL) { \ + for (j=0; jnb_baseURL; j++) { \ + gf_free(di->baseURL[j]); \ + } \ + gf_free(di->baseURL); \ + } \ + if (di->rep_descs) { \ + for (j=0; jnb_rep_descs; j++) { \ + gf_free(di->rep_descs[j]); \ + } \ + gf_free(di->rep_descs); \ + } \ + if (di->as_descs) { \ + for (j=0; jnb_as_descs; j++) { \ + gf_free(di->as_descs[j]); \ + } \ + gf_free(di->as_descs); \ + }\ + if (di->as_c_descs) { \ + for (j=0; jnb_as_c_descs; j++) { \ + gf_free(di->as_c_descs[j]); \ + } \ + gf_free(di->as_c_descs); \ + } \ + if (di->p_descs) { \ + for (j=0; jnb_p_descs; j++) { \ + gf_free(di->p_descs[j]); \ + } \ + gf_free(di->p_descs); \ + } \ + if (di->representationID) gf_free(di->representationID); \ + if (di->periodID) gf_free(di->periodID); \ + if (di->xlink) gf_free(di->xlink); \ + if (di->role) gf_free(di->role); \ + }\ + gf_free(dash_inputs); \ + } \ + gf_sys_close(); \ + if (__ret_code) return __ret_code; \ + goto exit; \ + + +GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char *name, u32 *nb_dash_inputs) +{ + GF_DashSegmenterInput *di; + char *sep; + // skip ./ and ../, and look for first . to figure out extension + if ((name[1]=='/') || (name[2]=='/') || (name[1]=='\\') || (name[2]=='\\') ) sep = strchr(name+3, '.'); + else { + char *s2 = strchr(name, ':'); + sep = strchr(name, '.'); + if (sep && s2 && (s2 - sep) < 0) { + sep = name; + } + } + + //then look for our opt separator : + sep = strchr(sep ? sep : name, ':'); + + if (sep && (sep[1]=='\\')) sep = strchr(sep+1, ':'); + + dash_inputs = gf_realloc(dash_inputs, sizeof(GF_DashSegmenterInput) * (*nb_dash_inputs + 1) ); + memset(&dash_inputs[*nb_dash_inputs], 0, sizeof(GF_DashSegmenterInput) ); + di = &dash_inputs[*nb_dash_inputs]; + (*nb_dash_inputs)++; + + if (sep) { + char *opts = sep+1; + sep[0] = 0; + while (opts) { + sep = strchr(opts, ':'); + while (sep) { + /* this is a real separator if it is followed by a keyword we are looking for */ + if (!strnicmp(sep, ":id=", 4) || + !strnicmp(sep, ":period=", 8) || + !strnicmp(sep, ":BaseURL=", 9) || + !strnicmp(sep, ":bandwidth=", 11) || + !strnicmp(sep, ":role=", 6) || + !strnicmp(sep, ":desc", 5) || + !strnicmp(sep, ":duration=", 10) || + !strnicmp(sep, ":xlink=", 7)) { + break; + } else { + sep = strchr(sep+1, ':'); + } + } + if (sep && !strncmp(sep, "://", 3)) sep = strchr(sep+3, ':'); + if (sep) sep[0] = 0; + + if (!strnicmp(opts, "id=", 3)) { + u32 i; + di->representationID = gf_strdup(opts+3); + /* check to see if this representation Id has already been assigned */ + for (i=0; i<(*nb_dash_inputs)-1; i++) { + GF_DashSegmenterInput *other_di; + other_di = &dash_inputs[i]; + if (!strcmp(other_di->representationID, di->representationID)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error: Duplicate Representation ID \"%s\" in command line\n", di->representationID)); + } + } + } else if (!strnicmp(opts, "period=", 7)) di->periodID = gf_strdup(opts+7); + else if (!strnicmp(opts, "BaseURL=", 8)) { + di->baseURL = (char **)gf_realloc(di->baseURL, (di->nb_baseURL+1)*sizeof(char *)); + di->baseURL[di->nb_baseURL] = gf_strdup(opts+8); + di->nb_baseURL++; + } else if (!strnicmp(opts, "bandwidth=", 10)) di->bandwidth = atoi(opts+10); + else if (!strnicmp(opts, "role=", 5)) di->role = gf_strdup(opts+5); + else if (!strnicmp(opts, "desc", 4)) { + u32 *nb_descs=NULL; + char ***descs=NULL; + u32 opt_offset=0; + u32 len; + if (!strnicmp(opts, "desc_p=", 7)) { + nb_descs = &di->nb_p_descs; + descs = &di->p_descs; + opt_offset = 7; + } else if (!strnicmp(opts, "desc_as=", 8)) { + nb_descs = &di->nb_as_descs; + descs = &di->as_descs; + opt_offset = 8; + } else if (!strnicmp(opts, "desc_as_c=", 8)) { + nb_descs = &di->nb_as_c_descs; + descs = &di->as_c_descs; + opt_offset = 10; + } else if (!strnicmp(opts, "desc_rep=", 8)) { + nb_descs = &di->nb_rep_descs; + descs = &di->rep_descs; + opt_offset = 9; + } + if (opt_offset) { + (*nb_descs)++; + opts += opt_offset; + len = (u32) strlen(opts); + (*descs) = (char **)gf_realloc((*descs), (*nb_descs)*sizeof(char *)); + (*descs)[(*nb_descs)-1] = (char *)gf_malloc((len+1)*sizeof(char)); + strncpy((*descs)[(*nb_descs)-1], opts, len); + (*descs)[(*nb_descs)-1][len] = 0; + } + + } + else if (!strnicmp(opts, "xlink=", 6)) di->xlink = gf_strdup(opts+6); + else if (!strnicmp(opts, "duration=", 9)) { + di->period_duration = (Double) atof(opts+9); + } + + if (!sep) break; + sep[0] = ':'; + opts = sep+1; + } + } + di->file_name = name; + if (!di->representationID) { + char szRep[100]; + sprintf(szRep, "%d", *nb_dash_inputs); + di->representationID = gf_strdup(szRep); + } + + return dash_inputs; +} + +static GF_Err parse_track_action_params(char *string, TrackAction *action) +{ + char *param = string; + while (param) { + param = strchr(param, ':'); + if (param) { + *param = 0; + param++; +#ifndef GPAC_DISABLE_MEDIA_EXPORT + if (!strncmp("vttnomerge", param, 10)) { + action->dump_type |= GF_EXPORT_WEBVTT_NOMERGE; + } else if (!strncmp("layer", param, 5)) { + action->dump_type |= GF_EXPORT_SVC_LAYER; + } else if (!strncmp("full", param, 4)) { + action->dump_type |= GF_EXPORT_NHML_FULL; + } else if (!strncmp("embedded", param, 8)) { + action->dump_type |= GF_EXPORT_WEBVTT_META_EMBEDDED; + } else if (!strncmp("output=", param, 7)) { + action->out_name = gf_strdup(param+7); + } else if (!strncmp("src=", param, 4)) { + action->src_name = gf_strdup(param+4); + } else if (!strncmp("box=", param, 4)) { + action->src_name = gf_strdup(param+4); + action->sample_num = 1; + } else if (!strncmp("type=", param, 4)) { + action->udta_type = GF_4CC(param[5], param[6], param[7], param[8]); + } else if (action->dump_type == GF_EXPORT_RAW_SAMPLES) { + action->sample_num = atoi(param); + } +#endif + } + } + if (!strcmp(string, "*")) { + action->trackID = (u32) -1; + } else { + action->trackID = atoi(string); + } + return GF_OK; +} + +static u32 create_new_track_action(char *string, TrackAction **actions, u32 *nb_track_act, u32 dump_type) +{ + *actions = (TrackAction *)gf_realloc(*actions, sizeof(TrackAction) * (*nb_track_act+1)); + memset(&(*actions)[*nb_track_act], 0, sizeof(TrackAction) ); + (*actions)[*nb_track_act].act_type = TRAC_ACTION_RAW_EXTRACT; + (*actions)[*nb_track_act].dump_type = dump_type; + parse_track_action_params(string, &(*actions)[*nb_track_act]); + (*nb_track_act)++; + return dump_type; +} + +static GF_Err nhml_bs_to_bin(char *inName, char *outName, u32 dump_std) +{ + GF_Err e; + GF_XMLNode *root; + char *data = NULL; + u32 data_size; + + GF_DOMParser *dom = gf_xml_dom_new(); + e = gf_xml_dom_parse(dom, inName, NULL, NULL); + if (e) { + gf_xml_dom_del(dom); + fprintf(stderr, "Failed to parse XML file: %s\n", gf_error_to_string(e)); + return e; + } + root = gf_xml_dom_get_root_idx(dom, 0); + if (!root) { + gf_xml_dom_del(dom); + return GF_OK; + } + + e = gf_xml_parse_bit_sequence(root, &data, &data_size); + gf_xml_dom_del(dom); + + if (e) { + fprintf(stderr, "Failed to parse binary sequence: %s\n", gf_error_to_string(e)); + return e; + } + + if (dump_std) { + fwrite(data, 1, data_size, stdout); + } else { + FILE *t; + char szFile[GF_MAX_PATH]; + if (outName) { + strcpy(szFile, outName); + } else { + strcpy(szFile, inName); + strcat(szFile, ".bin"); + } + t = gf_fopen(szFile, "wb"); + if (!t) { + fprintf(stderr, "Failed to open file %s\n", szFile); + e = GF_IO_ERR; + } else { + if (fwrite(data, 1, data_size, t) != data_size) { + fprintf(stderr, "Failed to write output to file %s\n", szFile); + e = GF_IO_ERR; + } + gf_fclose(t); + } + } + gf_free(data); + return e; +} + + +static GF_Err hash_file(char *name, u32 dump_std) +{ + u32 i; + u8 hash[20]; + GF_Err e = gf_media_get_file_hash(name, hash); + if (e) return e; + if (dump_std==2) { + fwrite(hash, 1, 20, stdout); + } else if (dump_std==1) { + for (i=0; i<20; i++) fprintf(stdout, "%02X", hash[i]); + } + fprintf(stderr, "File hash (SHA-1): "); + for (i=0; i<20; i++) fprintf(stderr, "%02X", hash[i]); + fprintf(stderr, "\n"); + + return GF_OK; +} + +static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) +{ + FILE *logs = cbk; + vfprintf(logs, fmt, list); + fflush(logs); +} + +int mp4boxMain(int argc, char **argv) +{ + char outfile[5000]; + GF_Err e; +#ifndef GPAC_DISABLE_SCENE_ENCODER + GF_SMEncodeOptions opts; +#endif + SDPLine *sdp_lines = NULL; + Double interleaving_time, split_duration, split_start, import_fps, dash_duration, dash_subduration; + MetaAction *metas = NULL; + TrackAction *tracks = NULL; + TSELAction *tsel_acts = NULL; + u64 movie_time, initial_tfdt; + s32 subsegs_per_sidx; + u32 *brand_add = NULL; + u32 *brand_rem = NULL; + GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_DEFAULT; + u32 i, stat_level, hint_flags, info_track_id, import_flags, nb_add, nb_cat, crypt, agg_samples, nb_sdp_ex, max_ptime, raw_sample_num, split_size, nb_meta_act, nb_track_act, rtp_rate, major_brand, nb_alt_brand_add, nb_alt_brand_rem, old_interleave, car_dur, minor_version, conv_type, nb_tsel_acts, program_number, dump_nal, time_shift_depth, initial_moof_sn, dump_std, import_subtitle; + GF_DashDynamicMode dash_mode=GF_DASH_STATIC; +#ifndef GPAC_DISABLE_SCENE_DUMP + GF_SceneDumpFormat dump_mode; +#endif + Double mpd_live_duration = 0; + Bool HintIt, needSave, FullInter, Frag, HintInter, dump_rtp, regular_iod, remove_sys_tracks, remove_hint, force_new, remove_root_od; + Bool print_sdp, print_info, open_edit, dump_isom, dump_cr, force_ocr, encode, do_log, do_flat, dump_srt, dump_ttxt, dump_timestamps, do_saf, dump_m2ts, dump_cart, do_hash, verbose, force_cat, align_cat, pack_wgt, single_group, dash_live, no_fragments_defaults, single_traf_per_moof; + char *inName, *outName, *arg, *mediaSource, *tmpdir, *input_ctx, *output_ctx, *drm_file, *avi2raw, *cprt, *chap_file, *pes_dump, *itunes_tags, *pack_file, *raw_cat, *seg_name, *dash_ctx_file; + u32 track_dump_type; + u32 trackID; + Double min_buffer = 1.5; + s32 ast_offset_ms = 0; + u32 dump_chap = 0; + u32 dump_udta_type = 0; + u32 dump_udta_track = 0; + char **mpd_base_urls = NULL; + u32 nb_mpd_base_urls=0; + u32 dash_scale = 1000; + Bool insert_utc = GF_FALSE; + +#ifndef GPAC_DISABLE_MPD + Bool do_mpd = 0; +#endif +#ifndef GPAC_DISABLE_SCENE_ENCODER + Bool chunk_mode=0; +#endif +#ifndef GPAC_DISABLE_ISOM_HINTING + Bool HintCopy=0; + u32 MTUSize = 1450; +#endif + GF_ISOFile *file; + Bool frag_real_time = 0; + Double mpd_update_time = 0; + Bool stream_rtp=0; + Bool force_co64 = GF_FALSE; + Bool live_scene=0; + Bool enable_mem_tracker = 0; + Bool dump_iod=0; + Bool pssh_in_moof=0; + Bool samplegroups_in_traf=0; + Bool daisy_chain_sidx=0; + Bool single_segment=0; + Bool single_file=0; + Bool segment_timeline=0; + u32 segment_marker = 0; + GF_DashProfile dash_profile = GF_DASH_PROFILE_UNKNOWN; + const char *dash_profile_extension = NULL; + Bool use_url_template=0; + Bool seg_at_rap=0; + Bool frag_at_rap=0; + Bool adjust_split_end = 0; + Bool memory_frags = 1; + Bool keep_utc = 0; + Bool do_bin_nhml = 0; + u32 timescale = 0; + const char *do_wget = NULL; + GF_DashSegmenterInput *dash_inputs = NULL; + u32 nb_dash_inputs = 0; + char *gf_logs = NULL; + char *seg_ext = NULL; + const char *dash_title = NULL; + const char *dash_source = NULL; + const char *dash_more_info = NULL; +#if !defined(GPAC_DISABLE_STREAMING) + const char *grab_m2ts = NULL; + const char *grab_ifce = NULL; +#endif + FILE *logfile = NULL; + + nb_tsel_acts = nb_add = nb_cat = nb_track_act = nb_sdp_ex = max_ptime = raw_sample_num = nb_meta_act = rtp_rate = major_brand = nb_alt_brand_add = nb_alt_brand_rem = car_dur = minor_version = 0; + e = GF_OK; + split_duration = 0.0; + split_start = -1.0; + interleaving_time = 0.0; + dash_duration = dash_subduration = 0.0; + import_fps = 0; + import_flags = 0; + split_size = 0; + movie_time = 0; + dump_nal = 0; + FullInter = HintInter = encode = do_log = old_interleave = do_saf = do_hash = verbose = 0; +#ifndef GPAC_DISABLE_SCENE_DUMP + dump_mode = GF_SM_DUMP_NONE; +#endif + Frag = force_ocr = remove_sys_tracks = agg_samples = remove_hint = keep_sys_tracks = remove_root_od = single_group = 0; + conv_type = HintIt = needSave = print_sdp = print_info = regular_iod = dump_std = open_edit = dump_isom = dump_rtp = dump_cr = dump_srt = dump_ttxt = force_new = dump_timestamps = dump_m2ts = dump_cart = import_subtitle = force_cat = pack_wgt = dash_live = 0; + no_fragments_defaults = 0; + single_traf_per_moof = 0, + /*align cat is the new default behaviour for -cat*/ + align_cat = 1; + subsegs_per_sidx = 0; + track_dump_type = 0; + crypt = 0; + time_shift_depth = 0; + file = NULL; + itunes_tags = pes_dump = NULL; + seg_name = dash_ctx_file = NULL; + initial_moof_sn = 0; + initial_tfdt = 0; + +#ifndef GPAC_DISABLE_SCENE_ENCODER + memset(&opts, 0, sizeof(opts)); +#endif + + trackID = stat_level = hint_flags = 0; + program_number = 0; + info_track_id = 0; + do_flat = 0; + inName = outName = mediaSource = input_ctx = output_ctx = drm_file = avi2raw = cprt = chap_file = pack_file = raw_cat = NULL; + +#ifndef GPAC_DISABLE_SWF_IMPORT + swf_flags = GF_SM_SWF_SPLIT_TIMELINE; +#endif + swf_flatten_angle = 0.0f; + tmpdir = NULL; + + for (i = 1; i < (u32) argc ; i++) { + if (!strcmp(argv[i], "-mem-track")) { +#ifdef GPAC_MEMORY_TRACKING + enable_mem_tracker = 1; +#else + fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n"); +#endif + break; + } + } + + /*init libgpac*/ + gf_sys_init(enable_mem_tracker); + if (argc < 2) { + PrintUsage(); + MP4BOX_EXIT_WITH_CODE(1); + } + + + /*parse our args*/ + for (i = 1; i < (u32) argc ; i++) { + arg = argv[i]; + /*input file(s)*/ + if ((arg[0] != '-') || !stricmp(arg, "--")) { + char *arg_val = arg; + if (!stricmp(arg, "--")) { + CHECK_NEXT_ARG + arg_val = argv[i+1]; + i++; + } + if (argc < 3) { + fprintf(stderr, "Error - only one input file found as argument, please check usage\n"); + MP4BOX_EXIT_WITH_CODE(1); + } else if (inName) { + if (dash_duration) { + if (!nb_dash_inputs) { + dash_inputs = set_dash_input(dash_inputs, inName, &nb_dash_inputs); + } + dash_inputs = set_dash_input(dash_inputs, arg_val, &nb_dash_inputs); + } else { + fprintf(stderr, "Error - 2 input names specified, please check usage\n"); + MP4BOX_EXIT_WITH_CODE(1); + } + } else { + inName = arg_val; + } + } + else if (!stricmp(arg, "-?")) { + PrintUsage(); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-version")) { + PrintVersion(); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-sdp")) print_sdp = 1; + else if (!stricmp(arg, "-quiet")) quiet = 2; + else if (!strcmp(argv[i], "-mem-track")) continue; + + else if (!stricmp(arg, "-logs")) { + CHECK_NEXT_ARG + gf_logs = argv[i+1]; + if (gf_logs) + gf_log_set_tools_levels(gf_logs); + i++; + } + else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) { + logfile = gf_fopen(argv[i+1], "wt"); + gf_log_set_callback(logfile, on_gpac_log); + i++; + } + else if (!stricmp(arg, "-noprog")) quiet = 1; + else if (!stricmp(arg, "-info")) { + print_info = 1; + if ((i+1<(u32) argc) && (sscanf(argv[i+1], "%u", &info_track_id)==1)) { + char szTk[20]; + sprintf(szTk, "%u", info_track_id); + if (!strcmp(szTk, argv[i+1])) i++; + else info_track_id=0; + } else { + info_track_id=0; + } + } +#if !defined(GPAC_DISABLE_STREAMING) + else if (!stricmp(arg, "-grab-ts")) { + CHECK_NEXT_ARG + grab_m2ts = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-ifce")) { + CHECK_NEXT_ARG + grab_ifce = argv[i+1]; + i++; + } + +#endif +#if !defined(GPAC_DISABLE_CORE_TOOLS) + else if (!stricmp(arg, "-wget")) { + CHECK_NEXT_ARG + do_wget = argv[i+1]; + i++; + } +#endif + /*******************************************************************************/ + else if (!stricmp(arg, "-dvbhdemux")) { + dvbhdemux = 1; + } + /********************************************************************************/ +#ifndef GPAC_DISABLE_MEDIA_EXPORT + else if (!stricmp(arg, "-raw")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE); + i++; + } + else if (!stricmp(arg, "-raw-layer")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER); + i++; + } + else if (!stricmp(arg, "-qcp")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP); + i++; + } + else if (!stricmp(arg, "-aviraw")) { + CHECK_NEXT_ARG + if (argv[i+1] && !stricmp(argv[i+1], "video")) trackID = 1; + else if (argv[i+1] && !stricmp(argv[i+1], "audio")) { + if (strlen(argv[i+1])==5) trackID = 2; + else trackID = 1 + atoi(argv[i+1] + 5); + } + else { + fprintf(stderr, "Usage: \"-aviraw video\" or \"-aviraw audio\"\n"); + MP4BOX_EXIT_WITH_CODE(1); + } + track_dump_type = GF_EXPORT_AVI_NATIVE; + i++; + } + else if (!stricmp(arg, "-raws")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_RAW_SAMPLES); + i++; + } + else if (!stricmp(arg, "-nhnt")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NHNT); + i++; + } + else if (!stricmp(arg, "-nhml")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NHML); + i++; + } + else if (!stricmp(arg, "-webvtt-raw")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_WEBVTT_META); + i++; + } + else if (!stricmp(arg, "-six")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_SIX); + i++; + } + else if (!stricmp(arg, "-avi")) { + CHECK_NEXT_ARG + track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_AVI); + i++; + } +#endif /*GPAC_DISABLE_MEDIA_EXPORT*/ +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + else if (!stricmp(arg, "-rtp")) { + stream_rtp = 1; + } + else if (!stricmp(arg, "-live")) { + live_scene = 1; + } +#endif + else if (!stricmp(arg, "-diod")) { + dump_iod = 1; + } +#ifndef GPAC_DISABLE_VRML + else if (!stricmp(arg, "-node")) { + CHECK_NEXT_ARG PrintNode(argv[i+1], 0); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-xnode")) { + CHECK_NEXT_ARG PrintNode(argv[i+1], 1); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-nodes")) { + PrintBuiltInNodes(0); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-xnodes")) { + PrintBuiltInNodes(1); + MP4BOX_EXIT_WITH_CODE(0); + } +#endif +#ifndef GPAC_DISABLE_SVG + else if (!stricmp(arg, "-snode")) { + CHECK_NEXT_ARG PrintNode(argv[i+1], 2); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-snodes")) { + PrintBuiltInNodes(2); + MP4BOX_EXIT_WITH_CODE(0); + } +#endif + else if (!stricmp(arg, "-std")) dump_std = 2; + else if (!stricmp(arg, "-stdb")) dump_std = 1; + +#if !defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_SCENE_DUMP) + else if (!stricmp(arg, "-bt")) dump_mode = GF_SM_DUMP_BT; + else if (!stricmp(arg, "-xmt")) dump_mode = GF_SM_DUMP_XMTA; + else if (!stricmp(arg, "-wrl")) dump_mode = GF_SM_DUMP_VRML; + else if (!stricmp(arg, "-x3dv")) dump_mode = GF_SM_DUMP_X3D_VRML; + else if (!stricmp(arg, "-x3d")) dump_mode = GF_SM_DUMP_X3D_XML; + else if (!stricmp(arg, "-lsr")) dump_mode = GF_SM_DUMP_LASER; + else if (!stricmp(arg, "-svg")) dump_mode = GF_SM_DUMP_SVG; +#endif /*defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_SCENE_DUMP)*/ + + else if (!stricmp(arg, "-stat")) stat_level = 1; + else if (!stricmp(arg, "-stats")) stat_level = 2; + else if (!stricmp(arg, "-statx")) stat_level = 3; + else if (!stricmp(arg, "-diso")) dump_isom = 1; + else if (!stricmp(arg, "-dump-cover")) dump_cart = 1; + else if (!stricmp(arg, "-dump-chap")) dump_chap = 1; + else if (!stricmp(arg, "-dump-chap-ogg")) dump_chap = 2; + else if (!stricmp(arg, "-hash")) do_hash = 1; + else if (!stricmp(arg, "-bin")) do_bin_nhml = 1; + else if (!stricmp(arg, "-dump-udta")) { + char *sep, *code; + CHECK_NEXT_ARG + sep = strchr(argv[i+1], ':'); + if (sep) { + sep[0] = 0; + dump_udta_track = atoi(argv[i+1]); + sep[0] = ':'; + code = &sep[1]; + } else { + code = argv[i+1]; + } + dump_udta_type = GF_4CC(code[0], code[1], code[2], code[3]); + i++; + } + + +#if 0 + else if (!stricmp(arg, "-conf")) { + if (i+1==(u32)argc) { + fprintf(stderr, "Missing arg - please check usage\n"); + MP4BOX_EXIT_WITH_CODE(1); + } + if (i+2==(u32)argc) { + gf_check_isom_files(NULL, argv[i+1]); + } else { + gf_check_isom_files(argv[i+1], argv[i+2]); + } + MP4BOX_EXIT_WITH_CODE(0); + } +#endif + else if (!stricmp(arg, "-dmp4")) { + dump_isom = 1; + fprintf(stderr, "WARNING: \"-dmp4\" is deprecated - use \"-diso\" option\n"); + } + else if (!stricmp(arg, "-drtp")) dump_rtp = 1; + else if (!stricmp(arg, "-dts")) { + dump_timestamps = 1; + if ( ((i+1<(u32) argc) && inName) || (i+2<(u32) argc) ) { + if (argv[i+1][0] != '-') program_number = atoi(argv[i+1]); + i++; + } + } else if (!stricmp(arg, "-dnal")) { + CHECK_NEXT_ARG + dump_nal = atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-dcr")) dump_cr = 1; + else if (!stricmp(arg, "-ttxt") || !stricmp(arg, "-srt")) { + if ((i+1<(u32) argc) && (sscanf(argv[i+1], "%u", &trackID)==1)) { + char szTk[20]; + sprintf(szTk, "%d", trackID); + if (!strcmp(szTk, argv[i+1])) i++; + else trackID=0; + } else { + trackID = 0; + } +#ifdef GPAC_DISABLE_ISOM_WRITE + if (trackID) { + fprintf(stderr, "Error: Read-Only version - subtitle conversion not available\n"); + MP4BOX_EXIT_WITH_CODE(1); + } +#endif + if (!stricmp(arg, "-ttxt")) dump_ttxt = GF_TRUE; + else dump_srt = GF_TRUE; + import_subtitle = 1; + } else if (!stricmp(arg, "-dm2ts")) { + dump_m2ts = 1; + if ( ((i+1<(u32) argc) && inName) || (i+2<(u32) argc) ) { + if (argv[i+1][0] != '-') pes_dump = argv[i+1]; + i++; + } + } + +#ifndef GPAC_DISABLE_SWF_IMPORT + /*SWF importer options*/ + else if (!stricmp(arg, "-global")) swf_flags |= GF_SM_SWF_STATIC_DICT; + else if (!stricmp(arg, "-no-ctrl")) swf_flags &= ~GF_SM_SWF_SPLIT_TIMELINE; + else if (!stricmp(arg, "-no-text")) swf_flags |= GF_SM_SWF_NO_TEXT; + else if (!stricmp(arg, "-no-font")) swf_flags |= GF_SM_SWF_NO_FONT; + else if (!stricmp(arg, "-no-line")) swf_flags |= GF_SM_SWF_NO_LINE; + else if (!stricmp(arg, "-no-grad")) swf_flags |= GF_SM_SWF_NO_GRADIENT; + else if (!stricmp(arg, "-quad")) swf_flags |= GF_SM_SWF_QUAD_CURVE; + else if (!stricmp(arg, "-xlp")) swf_flags |= GF_SM_SWF_SCALABLE_LINE; + else if (!stricmp(arg, "-ic2d")) swf_flags |= GF_SM_SWF_USE_IC2D; + else if (!stricmp(arg, "-same-app")) swf_flags |= GF_SM_SWF_REUSE_APPEARANCE; + else if (!stricmp(arg, "-flatten")) { + CHECK_NEXT_ARG + swf_flatten_angle = (Float) atof(argv[i+1]); + i++; + } +#endif +#ifndef GPAC_DISABLE_ISOM_WRITE + else if (!stricmp(arg, "-isma")) { + conv_type = GF_ISOM_CONV_TYPE_ISMA; + open_edit = 1; + } + else if (!stricmp(arg, "-3gp")) { + conv_type = GF_ISOM_CONV_TYPE_3GPP; + open_edit = 1; + } + else if (!stricmp(arg, "-ipod")) { + conv_type = GF_ISOM_CONV_TYPE_IPOD; + open_edit = 1; + } + else if (!stricmp(arg, "-psp")) { + conv_type = GF_ISOM_CONV_TYPE_PSP; + open_edit = 1; + } + else if (!stricmp(arg, "-ismax")) { + conv_type = GF_ISOM_CONV_TYPE_ISMA_EX; + open_edit = 1; + } + + else if (!stricmp(arg, "-no-sys") || !stricmp(arg, "-nosys")) { + remove_sys_tracks = 1; + open_edit = 1; + } + else if (!stricmp(arg, "-no-iod")) { + remove_root_od = 1; + open_edit = 1; + } + else if (!stricmp(arg, "-out")) { + CHECK_NEXT_ARG outName = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-tmp")) { + CHECK_NEXT_ARG tmpdir = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-co64")) { + force_co64 = GF_TRUE; + open_edit = 1; + } + else if (!stricmp(arg, "-write-buffer")) { + CHECK_NEXT_ARG + gf_isom_set_output_buffering(NULL, atoi(argv[i+1])); + i++; + } + else if (!stricmp(arg, "-cprt")) { + CHECK_NEXT_ARG cprt = argv[i+1]; + i++; + if (!dash_duration) open_edit = 1; + } + else if (!stricmp(arg, "-chap")) { + CHECK_NEXT_ARG chap_file = argv[i+1]; + i++; + open_edit = 1; + } + else if (!strcmp(arg, "-strict-error")) { + gf_log_set_strict_error(1); + } else if (!stricmp(arg, "-inter") || !stricmp(arg, "-old-inter")) { + CHECK_NEXT_ARG + interleaving_time = atof(argv[i+1]) / 1000; + open_edit = 1; + needSave = 1; + if (!stricmp(arg, "-old-inter")) old_interleave = 1; + i++; + } else if (!stricmp(arg, "-frag")) { + CHECK_NEXT_ARG + interleaving_time = atof(argv[i+1]) / 1000; + needSave = 1; + i++; + Frag = 1; + } else if (!stricmp(arg, "-dash")) { + CHECK_NEXT_ARG + dash_duration = atof(argv[i+1]) / 1000; + if (dash_duration == 0.0) { + fprintf(stderr, "\tERROR: \"-dash-dash_duration\": invalid parameter %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + i++; + } else if (!stricmp(arg, "-subdur")) { + CHECK_NEXT_ARG + dash_subduration = atof(argv[i+1]) / 1000; + i++; + } else if (!stricmp(arg, "-dash-scale")) { + CHECK_NEXT_ARG + dash_scale = atoi(argv[i+1]); + if (!dash_scale) { + fprintf(stderr, "\tERROR: \"-dash-scale\": invalid parameter %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + i++; + } else if (!stricmp(arg, "-dash-ts-prog")) { + CHECK_NEXT_ARG + program_number = atoi(argv[i+1]); + i++; + } else if (!stricmp(arg, "-subsegs-per-sidx") || !stricmp(arg, "-frags-per-sidx")) { + CHECK_NEXT_ARG + subsegs_per_sidx = atoi(argv[i+1]); + i++; + } else if (!stricmp(arg, "-segment-name")) { + CHECK_NEXT_ARG + seg_name = argv[i+1]; + i++; + } else if (!stricmp(arg, "-segment-ext")) { + CHECK_NEXT_ARG + seg_ext = argv[i+1]; + i++; + } else if (!stricmp(arg, "-bs-switching")) { + CHECK_NEXT_ARG + if (!stricmp(argv[i+1], "no") || !stricmp(argv[i+1], "off")) bitstream_switching_mode = GF_DASH_BSMODE_NONE; + else if (!stricmp(argv[i+1], "merge")) bitstream_switching_mode = GF_DASH_BSMODE_MERGED; + else if (!stricmp(argv[i+1], "multi")) bitstream_switching_mode = GF_DASH_BSMODE_MULTIPLE_ENTRIES; + else if (!stricmp(argv[i+1], "single")) bitstream_switching_mode = GF_DASH_BSMODE_SINGLE; + else if (!stricmp(argv[i+1], "inband")) bitstream_switching_mode = GF_DASH_BSMODE_INBAND; + else { + fprintf(stderr, "\tWARNING: Unrecognized bitstream switchin mode \"%s\" - please check usage\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + i++; + } + else if (!stricmp(arg, "-dynamic")) { + dash_mode = GF_DASH_DYNAMIC; + } + else if (!stricmp(arg, "-last-dynamic")) { + dash_mode = GF_DASH_DYNAMIC_LAST; + } + else if (!stricmp(arg, "-frag-rt")) { + frag_real_time = GF_TRUE; + } + else if (!strnicmp(arg, "-dash-live", 10) || !strnicmp(arg, "-ddbg-live", 10)) { + dash_mode = !strnicmp(arg, "-ddbg-live", 10) ? GF_DASH_DYNAMIC_DEBUG : GF_DASH_DYNAMIC; + dash_live = 1; + if (arg[10]=='=') { + dash_ctx_file = arg+11; + } + CHECK_NEXT_ARG + dash_duration = atof(argv[i+1]) / 1000; + i++; + } + else if (!stricmp(arg, "-mpd-duration")) { + CHECK_NEXT_ARG mpd_live_duration = atof(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-mpd-refresh")) { + CHECK_NEXT_ARG mpd_update_time = atof(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-time-shift")) { + CHECK_NEXT_ARG + time_shift_depth = (u32) atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-min-buffer")) { + CHECK_NEXT_ARG + min_buffer = atoi(argv[i+1]); + min_buffer /= 1000; + i++; + } + else if (!stricmp(arg, "-ast-offset")) { + CHECK_NEXT_ARG + ast_offset_ms = atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-moof-sn")) { + CHECK_NEXT_ARG + initial_moof_sn = (u32) atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-tfdt")) { + CHECK_NEXT_ARG + sscanf(argv[i+1], LLU, &initial_tfdt); + i++; + } + else if (!stricmp(arg, "-no-frags-default")) { + no_fragments_defaults = 1; + } + else if (!stricmp(arg, "-single-traf")) { + single_traf_per_moof = 1; + } + else if (!stricmp(arg, "-mpd-title")) { + CHECK_NEXT_ARG dash_title = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-mpd-source")) { + CHECK_NEXT_ARG dash_source = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-mpd-info-url")) { + CHECK_NEXT_ARG dash_more_info = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-base-url")) { + CHECK_NEXT_ARG + dash_more_info = argv[i+1]; + mpd_base_urls = gf_realloc(mpd_base_urls, (nb_mpd_base_urls+1)*sizeof(char**)); + mpd_base_urls[nb_mpd_base_urls] = argv[i+1]; + nb_mpd_base_urls++; + i++; + } + else if (!stricmp(arg, "-dash-ctx")) { + CHECK_NEXT_ARG + dash_ctx_file = argv[i+1]; + i++; + } else if (!stricmp(arg, "-daisy-chain")) { + daisy_chain_sidx = 1; + } else if (!stricmp(arg, "-single-segment")) { + single_segment = 1; + } else if (!stricmp(arg, "-single-file")) { + single_file = 1; + } else if (!stricmp(arg, "-pssh-moof")) { + pssh_in_moof = 1; + } else if (!stricmp(arg, "-sample-groups-traf")) { + samplegroups_in_traf = 1; + } else if (!stricmp(arg, "-dash-profile") || !stricmp(arg, "-profile")) { + CHECK_NEXT_ARG + if (!stricmp(argv[i+1], "live") || !stricmp(argv[i+1], "simple")) dash_profile = GF_DASH_PROFILE_LIVE; + else if (!stricmp(argv[i+1], "onDemand")) dash_profile = GF_DASH_PROFILE_ONDEMAND; + else if (!stricmp(argv[i+1], "hbbtv1.5:live")) { + dash_profile = GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE; + } else if (!stricmp(argv[i+1], "dashavc264:live")) { + dash_profile = GF_DASH_PROFILE_AVC264_LIVE; + } else if (!stricmp(argv[i+1], "dashavc264:onDemand")) { + dash_profile = GF_DASH_PROFILE_AVC264_ONDEMAND; + } else if (!stricmp(argv[i+1], "main")) dash_profile = GF_DASH_PROFILE_MAIN; + else dash_profile = GF_DASH_PROFILE_FULL; + i++; + } else if (!stricmp(arg, "-profile-ext")) { + CHECK_NEXT_ARG + dash_profile_extension = argv[i+1]; + i++; + } else if (!strnicmp(arg, "-url-template", 13)) { + use_url_template = 1; + if ((arg[13]=='=') && arg[14]) { + if (!strcmp( &arg[14], "simulate")) use_url_template = 2; + } + } else if (!stricmp(arg, "-segment-timeline")) { + segment_timeline = 1; + } else if (!stricmp(arg, "-mem-frags")) { + memory_frags = 1; + } else if (!stricmp(arg, "-segment-marker")) { + char *m; + CHECK_NEXT_ARG + m = argv[i+1]; + segment_marker = GF_4CC(m[0], m[1], m[2], m[3]); + i++; + } else if (!stricmp(arg, "-insert-utc")) { + insert_utc = GF_TRUE; + } else if (!stricmp(arg, "-itags")) { + CHECK_NEXT_ARG itunes_tags = argv[i+1]; + i++; + open_edit = 1; + } +#ifndef GPAC_DISABLE_ISOM_HINTING + else if (!stricmp(arg, "-hint")) { + open_edit = 1; + HintIt = 1; + } + else if (!stricmp(arg, "-unhint")) { + open_edit = 1; + remove_hint = 1; + } + else if (!stricmp(arg, "-copy")) HintCopy = 1; + else if (!stricmp(arg, "-tight")) { + FullInter = 1; + open_edit = 1; + needSave = 1; + } else if (!stricmp(arg, "-ocr")) force_ocr = 1; + else if (!stricmp(arg, "-latm")) hint_flags |= GP_RTP_PCK_USE_LATM_AAC; + else if (!stricmp(arg, "-rap")) { + if ((i+1 < (u32)argc) && (argv[i+1][0] != '-')) { + if (sscanf(argv[i+1], "%d", &trackID) == 1) { + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + tracks[nb_track_act].act_type = TRAC_ACTION_REM_NON_RAP; + tracks[nb_track_act].trackID = trackID; + nb_track_act++; + i++; + open_edit = 1; + } + } + hint_flags |= GP_RTP_PCK_SIGNAL_RAP; + seg_at_rap=1; + } + else if (!stricmp(arg, "-frag-rap")) { + frag_at_rap=1; + } + else if (!stricmp(arg, "-ts")) hint_flags |= GP_RTP_PCK_SIGNAL_TS; + else if (!stricmp(arg, "-size")) hint_flags |= GP_RTP_PCK_SIGNAL_SIZE; + else if (!stricmp(arg, "-idx")) hint_flags |= GP_RTP_PCK_SIGNAL_AU_IDX; + else if (!stricmp(arg, "-static")) hint_flags |= GP_RTP_PCK_USE_STATIC_ID; + else if (!stricmp(arg, "-multi")) { + hint_flags |= GP_RTP_PCK_USE_MULTI; + if ((i+1<(u32) argc) && (sscanf(argv[i+1], "%u", &max_ptime)==1)) { + char szPt[20]; + sprintf(szPt, "%u", max_ptime); + if (!strcmp(szPt, argv[i+1])) i++; + else max_ptime=0; + } + } +#endif + else if (!stricmp(arg, "-mpeg4")) { +#ifndef GPAC_DISABLE_ISOM_HINTING + hint_flags |= GP_RTP_PCK_FORCE_MPEG4; +#endif +#ifndef GPAC_DISABLE_MEDIA_IMPORT + import_flags |= GF_IMPORT_FORCE_MPEG4; +#endif + } +#ifndef GPAC_DISABLE_ISOM_HINTING + else if (!stricmp(arg, "-mtu")) { + CHECK_NEXT_ARG MTUSize = atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-cardur")) { + CHECK_NEXT_ARG car_dur = atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-rate")) { + CHECK_NEXT_ARG rtp_rate = atoi(argv[i+1]); + i++; + } +#ifndef GPAC_DISABLE_SENG + else if (!stricmp(arg, "-add-sdp") || !stricmp(arg, "-sdp_ex")) { + char *id; + CHECK_NEXT_ARG + sdp_lines = gf_realloc(sdp_lines, sizeof(SDPLine) * (nb_sdp_ex+1) ); + + id = strchr(argv[i+1], ':'); + if (id) { + id[0] = 0; + if (sscanf(argv[i+1], "%u", &sdp_lines[0].trackID)==1) { + id[0] = ':'; + sdp_lines[nb_sdp_ex].line = id+1; + } else { + id[0] = ':'; + sdp_lines[nb_sdp_ex].line = argv[i+1]; + sdp_lines[nb_sdp_ex].trackID = 0; + } + } else { + sdp_lines[nb_sdp_ex].line = argv[i+1]; + sdp_lines[nb_sdp_ex].trackID = 0; + } + open_edit = 1; + nb_sdp_ex++; + i++; + } +#endif /*GPAC_DISABLE_SENG*/ +#endif /*GPAC_DISABLE_ISOM_HINTING*/ + + else if (!stricmp(arg, "-single")) { +#ifndef GPAC_DISABLE_MEDIA_EXPORT + CHECK_NEXT_ARG + track_dump_type = GF_EXPORT_MP4; + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + tracks[nb_track_act].act_type = TRAC_ACTION_RAW_EXTRACT; + tracks[nb_track_act].trackID = atoi(argv[i+1]); + tracks[nb_track_act].dump_type = GF_EXPORT_MP4; + nb_track_act++; + i++; +#endif + } + else if (!stricmp(arg, "-iod")) regular_iod = 1; + else if (!stricmp(arg, "-flat")) { + open_edit = 1; + do_flat = 1; + } + else if (!stricmp(arg, "-keep-utc")) keep_utc = 1; + else if (!stricmp(arg, "-new")) force_new = 1; + else if (!stricmp(arg, "-timescale")) { + CHECK_NEXT_ARG + timescale = atoi(argv[i+1]); + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-udta")) { + CHECK_NEXT_ARG + create_new_track_action(argv[i+1], &tracks, &nb_track_act, 0); + tracks[nb_track_act-1].act_type = TRAC_ACTION_SET_UDTA; + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-add") || !stricmp(arg, "-import") || !stricmp(arg, "-convert")) { + CHECK_NEXT_ARG + if (!stricmp(arg, "-import")) fprintf(stderr, "\tWARNING: \"-import\" is deprecated - use \"-add\"\n"); + else if (!stricmp(arg, "-convert")) fprintf(stderr, "\tWARNING: \"-convert\" is deprecated - use \"-add\"\n"); + nb_add++; + i++; + } + else if (!stricmp(arg, "-cat") || !stricmp(arg, "-catx")) { + CHECK_NEXT_ARG + nb_cat++; + i++; + } + else if (!stricmp(arg, "-time")) { + struct tm time; + CHECK_NEXT_ARG + memset(&time, 0, sizeof(struct tm)); + sscanf(argv[i+1], "%d/%d/%d-%d:%d:%d", &time.tm_mday, &time.tm_mon, &time.tm_year, &time.tm_hour, &time.tm_min, &time.tm_sec); + time.tm_isdst=0; + time.tm_year -= 1900; + time.tm_mon -= 1; + open_edit = 1; + movie_time = 2082758400; + movie_time += mktime(&time); + i++; + } + else if (!stricmp(arg, "-force-cat")) force_cat = 1; + else if (!stricmp(arg, "-align-cat")) align_cat = 1; + else if (!stricmp(arg, "-unalign-cat")) align_cat = 0; + else if (!stricmp(arg, "-raw-cat")) { + CHECK_NEXT_ARG + raw_cat = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-rem") || !stricmp(arg, "-disable") || !stricmp(arg, "-enable")) { + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + if (!stricmp(arg, "-enable")) tracks[nb_track_act].act_type = TRAC_ACTION_ENABLE; + else if (!stricmp(arg, "-disable")) tracks[nb_track_act].act_type = TRAC_ACTION_DISABLE; + else tracks[nb_track_act].act_type = TRAC_ACTION_REM_TRACK; + tracks[nb_track_act].trackID = atoi(argv[i+1]); + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-set-track-id")) { + char *sep; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + tracks[nb_track_act].act_type = TRAC_ACTION_SET_ID; + sep = strchr(argv[i+1], ':'); + *sep = 0; + tracks[nb_track_act].trackID = atoi(argv[i+1]); + *sep = ':'; + sep++; + tracks[nb_track_act].newTrackID = atoi(sep); + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-par")) { + char szTK[20], *ext; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + + tracks[nb_track_act].act_type = TRAC_ACTION_SET_PAR; + assert(strlen(argv[i+1])+1 <= sizeof(szTK)); + strncpy(szTK, argv[i+1], sizeof(szTK)); + ext = strchr(szTK, '='); + if (!ext) { + fprintf(stderr, "Bad format for track par - expecting ID=PAR_NUM:PAR_DEN got %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + if (!stricmp(ext+1, "none")) { + tracks[nb_track_act].par_num = tracks[nb_track_act].par_den = -1; + } else { + sscanf(ext+1, "%d", &tracks[nb_track_act].par_num); + ext = strchr(ext+1, ':'); + if (!ext) { + fprintf(stderr, "Bad format for track par - expecting ID=PAR_NUM:PAR_DEN got %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + sscanf(ext+1, "%d", &tracks[nb_track_act].par_den); + } + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-lang")) { + char szTK[20], *ext; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + + tracks[nb_track_act].act_type = TRAC_ACTION_SET_LANGUAGE; + tracks[nb_track_act].trackID = 0; + strcpy(szTK, argv[i+1]); + ext = strchr(szTK, '='); + if (!strnicmp(argv[i+1], "all=", 4)) { + tracks[nb_track_act].lang = gf_strdup(argv[i+1]+4); + } else if (!ext) { + tracks[nb_track_act].lang = gf_strdup(argv[i+1]); + } else { + tracks[nb_track_act].lang = gf_strdup(ext+1); + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + ext[0] = '='; + } + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-kind") || !stricmp(arg, "-kind-rem")) { + char szTK[200], *ext; + char *scheme_start = NULL; + Bool has_track_id = GF_FALSE; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + + if (!stricmp(arg, "-kind")) { + tracks[nb_track_act].act_type = TRAC_ACTION_SET_KIND; + } else { + tracks[nb_track_act].act_type = TRAC_ACTION_REM_KIND; + } + tracks[nb_track_act].trackID = 0; + if (!strnicmp(argv[i+1], "all=", 4)) { + scheme_start = argv[i+1]+4; + has_track_id = GF_TRUE; + } + if (!scheme_start) { + if (strlen(argv[i+1])>200) { + GF_LOG(GF_LOG_WARNING, GF_LOG_ALL, ("Warning: track kind parameter is too long!")); + } + strncpy(szTK, argv[i+1], 200); + ext = strchr(szTK, '='); + if (ext && !has_track_id) { + ext[0] = 0; + has_track_id = (sscanf(szTK, "%d", &tracks[nb_track_act].trackID) == 1 ? GF_TRUE : GF_FALSE); + if (has_track_id) { + scheme_start = ext+1; + } else { + scheme_start = szTK; + } + ext[0] = '='; + } else { + scheme_start = szTK; + } + } + ext = strchr(scheme_start, '='); + if (!ext) { + tracks[nb_track_act].kind_scheme = gf_strdup(scheme_start); + } else { + ext[0] = 0; + tracks[nb_track_act].kind_scheme = gf_strdup(scheme_start); + ext[0] = '='; + tracks[nb_track_act].kind_value = gf_strdup(ext+1); + } + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-delay")) { + char szTK[20], *ext; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + + strcpy(szTK, argv[i+1]); + ext = strchr(szTK, '='); + if (!ext) { + fprintf(stderr, "Bad format for track delay - expecting ID=DLAY got %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + tracks[nb_track_act].act_type = TRAC_ACTION_SET_DELAY; + tracks[nb_track_act].delay_ms = atoi(ext+1); + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-ref")) { + char *szTK, *ext; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + + szTK = argv[i+1]; + ext = strchr(szTK, ':'); + if (!ext) { + fprintf(stderr, "Bad format for track reference - expecting ID:XXXX:refID got %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + tracks[nb_track_act].act_type = TRAC_ACTION_REFERENCE; + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + ext[0] = ':'; + szTK = ext+1; + ext = strchr(szTK, ':'); + if (!ext) { + fprintf(stderr, "Bad format for track reference - expecting ID:XXXX:refID got %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + ext[0] = 0; + tracks[nb_track_act].lang = gf_strdup(szTK); + ext[0] = ':'; + tracks[nb_track_act].delay_ms = (s32) atoi(ext+1); + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-name")) { + char szTK[GF_MAX_PATH], *ext; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + + strcpy(szTK, argv[i+1]); + ext = strchr(szTK, '='); + if (!ext) { + fprintf(stderr, "Bad format for track name - expecting ID=name got %s\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } + tracks[nb_track_act].act_type = TRAC_ACTION_SET_HANDLER_NAME; + tracks[nb_track_act].hdl_name = strchr(argv[i+1], '=') + 1; + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + ext[0] = '='; + open_edit = 1; + nb_track_act++; + i++; + } +#if !defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_MEDIA_IMPORT) + else if (!stricmp(arg, "-dref")) import_flags |= GF_IMPORT_USE_DATAREF; + else if (!stricmp(arg, "-no-drop") || !stricmp(arg, "-nodrop")) import_flags |= GF_IMPORT_NO_FRAME_DROP; + else if (!stricmp(arg, "-packed")) import_flags |= GF_IMPORT_FORCE_PACKED; + else if (!stricmp(arg, "-sbr")) import_flags |= GF_IMPORT_SBR_IMPLICIT; + else if (!stricmp(arg, "-sbrx")) import_flags |= GF_IMPORT_SBR_EXPLICIT; + else if (!stricmp(arg, "-ps")) import_flags |= GF_IMPORT_PS_IMPLICIT; + else if (!stricmp(arg, "-psx")) import_flags |= GF_IMPORT_PS_EXPLICIT; + else if (!stricmp(arg, "-ovsbr")) import_flags |= GF_IMPORT_OVSBR; + else if (!stricmp(arg, "-fps")) { + CHECK_NEXT_ARG + if (!strcmp(argv[i+1], "auto")) import_fps = GF_IMPORT_AUTO_FPS; + else if (strchr(argv[i+1], '-')) { + u32 ticks, dts_inc; + sscanf(argv[i+1], "%u-%u", &ticks, &dts_inc); + if (!dts_inc) dts_inc=1; + import_fps = ticks; + import_fps /= dts_inc; + } else import_fps = atof(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-agg")) { + CHECK_NEXT_ARG agg_samples = atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-keep-all") || !stricmp(arg, "-keepall")) import_flags |= GF_IMPORT_KEEP_ALL_TRACKS; +#endif /*!defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_MEDIA_IMPORT*/ + else if (!stricmp(arg, "-keep-sys") || !stricmp(arg, "-keepsys")) keep_sys_tracks = 1; + else if (!stricmp(arg, "-ms")) { + CHECK_NEXT_ARG mediaSource = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-mp4")) { + encode = 1; + open_edit = 1; + } + else if (!stricmp(arg, "-saf")) { + do_saf = 1; + } + else if (!stricmp(arg, "-log")) { + do_log = 1; + } +#ifndef GPAC_DISABLE_MPD + else if (!stricmp(arg, "-mpd")) { + do_mpd = 1; + CHECK_NEXT_ARG + inName = argv[i+1]; + i++; + } +#endif + +#ifndef GPAC_DISABLE_SCENE_ENCODER + else if (!stricmp(arg, "-def")) opts.flags |= GF_SM_ENCODE_USE_NAMES; + else if (!stricmp(arg, "-sync")) { + CHECK_NEXT_ARG + opts.flags |= GF_SM_ENCODE_RAP_INBAND; + opts.rap_freq = atoi(argv[i+1]); + i++; + } else if (!stricmp(arg, "-shadow")) { + CHECK_NEXT_ARG + opts.flags &= ~GF_SM_ENCODE_RAP_INBAND; + opts.flags |= GF_SM_ENCODE_RAP_SHADOW; + opts.rap_freq = atoi(argv[i+1]); + i++; + } else if (!stricmp(arg, "-carousel")) { + CHECK_NEXT_ARG + opts.flags &= ~(GF_SM_ENCODE_RAP_INBAND | GF_SM_ENCODE_RAP_SHADOW); + opts.rap_freq = atoi(argv[i+1]); + i++; + } + /*LASeR options*/ + else if (!stricmp(arg, "-resolution")) { + CHECK_NEXT_ARG + opts.resolution = atoi(argv[i+1]); + i++; + } +#ifndef GPAC_DISABLE_SCENE_STATS + else if (!stricmp(arg, "-auto-quant")) { + CHECK_NEXT_ARG + opts.resolution = atoi(argv[i+1]); + opts.auto_quant = 1; + i++; + } +#endif + else if (!stricmp(arg, "-coord-bits")) { + CHECK_NEXT_ARG + opts.coord_bits = atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-scale-bits")) { + CHECK_NEXT_ARG + opts.scale_bits = atoi(argv[i+1]); + i++; + } + else if (!stricmp(arg, "-global-quant")) { + CHECK_NEXT_ARG + opts.resolution = atoi(argv[i+1]); + opts.auto_quant = 2; + i++; + } + /*chunk encoding*/ + else if (!stricmp(arg, "-ctx-out") || !stricmp(arg, "-outctx")) { + CHECK_NEXT_ARG output_ctx = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-ctx-in") || !stricmp(arg, "-inctx")) { + CHECK_NEXT_ARG + chunk_mode = 1; + input_ctx = argv[i+1]; + i++; + } +#endif /*GPAC_DISABLE_SCENE_ENCODER*/ + else if (!strcmp(arg, "-crypt")) { + CHECK_NEXT_ARG + crypt = 1; + drm_file = argv[i+1]; + open_edit = 1; + i += 1; + } + else if (!strcmp(arg, "-decrypt")) { + CHECK_NEXT_ARG + crypt = 2; + if (get_file_type_by_ext(argv[i+1])!=1) { + drm_file = argv[i+1]; + i += 1; + } + open_edit = 1; + } + else if (!stricmp(arg, "-set-kms")) { + char szTK[20], *ext; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + + strncpy(szTK, argv[i+1], 19); + ext = strchr(szTK, '='); + tracks[nb_track_act].act_type = TRAC_ACTION_SET_KMS_URI; + tracks[nb_track_act].trackID = 0; + if (!strnicmp(argv[i+1], "all=", 4)) { + tracks[nb_track_act].kms = argv[i+1] + 4; + } else if (!ext) { + tracks[nb_track_act].kms = argv[i+1]; + } else { + tracks[nb_track_act].kms = ext+1; + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + ext[0] = '='; + } + open_edit = 1; + nb_track_act++; + i++; + } + else if (!stricmp(arg, "-split")) { + CHECK_NEXT_ARG + split_duration = atof(argv[i+1]); + if (split_duration<0) split_duration=0;; + i++; + split_size = 0; + } + else if (!stricmp(arg, "-split-rap") || !stricmp(arg, "-splitr")) { + CHECK_NEXT_ARG + split_duration = -1; + split_size = -1; + } + else if (!stricmp(arg, "-split-size") || !stricmp(arg, "-splits")) { + CHECK_NEXT_ARG + split_size = (u32) atoi(argv[i+1]); + i++; + split_duration = 0; + } + else if (!stricmp(arg, "-split-chunk") || !stricmp(arg, "-splitx") || !stricmp(arg, "-splitz")) { + CHECK_NEXT_ARG + if (!strstr(argv[i+1], ":")) { + fprintf(stderr, "Chunk extraction usage: \"-splitx start:end\" expressed in seconds\n"); + MP4BOX_EXIT_WITH_CODE(1); + } + if (strstr(argv[i+1], "end")) { + sscanf(argv[i+1], "%lf:end", &split_start); + split_duration = -2; + } else { + sscanf(argv[i+1], "%lf:%lf", &split_start, &split_duration); + split_duration -= split_start; + } + split_size = 0; + if (!stricmp(arg, "-splitz")) adjust_split_end = 1; + i++; + } + /*meta*/ + else if (!stricmp(arg, "-set-meta")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_TYPE, argv[i+1]); + nb_meta_act++; + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-add-item")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + parse_meta_args(&metas[nb_meta_act], META_ACTION_ADD_ITEM, argv[i+1]); + nb_meta_act++; + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-rem-item")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + parse_meta_args(&metas[nb_meta_act], META_ACTION_REM_ITEM, argv[i+1]); + nb_meta_act++; + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-set-primary")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_PRIMARY_ITEM, argv[i+1]); + nb_meta_act++; + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-set-xml")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_XML, argv[i+1]); + nb_meta_act++; + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-rem-xml")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + if (parse_meta_args(&metas[nb_meta_act], META_ACTION_REM_XML, argv[i+1])) i++; + nb_meta_act++; + open_edit = 1; + } + else if (!stricmp(arg, "-dump-xml")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + parse_meta_args(&metas[nb_meta_act], META_ACTION_DUMP_XML, argv[i+1]); + nb_meta_act++; + i++; + } + else if (!stricmp(arg, "-dump-item")) { + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); + parse_meta_args(&metas[nb_meta_act], META_ACTION_DUMP_ITEM, argv[i+1]); + nb_meta_act++; + i++; + } + else if (!stricmp(arg, "-group-add") || !stricmp(arg, "-group-rem-track") || !stricmp(arg, "-group-rem")) { + TSELActionType act_type; + if (!stricmp(arg, "-group-rem")) { + act_type = TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP; + } else if ( !stricmp(arg, "-group-rem-track")) { + act_type = TSEL_ACTION_REMOVE_TSEL; + } else { + act_type = TSEL_ACTION_SET_PARAM; + } + if (parse_tsel_args(&tsel_acts, argv[i+1], &nb_tsel_acts, act_type)==0) { + fprintf(stderr, "Invalid group syntax - check usage\n"); + MP4BOX_EXIT_WITH_CODE(1); + } + open_edit=1; + i++; + } + else if (!stricmp(arg, "-group-clean")) { + tsel_acts[nb_tsel_acts].act_type = TSEL_ACTION_REMOVE_ALL_TSEL_IN_FILE; + nb_tsel_acts++; + open_edit=1; + } + else if (!stricmp(arg, "-group-single")) { + single_group = 1; + } + else if (!stricmp(arg, "-package")) { + CHECK_NEXT_ARG + pack_file = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-mgt")) { + CHECK_NEXT_ARG + pack_file = argv[i+1]; + pack_wgt = 1; + i++; + } + + else if (!stricmp(arg, "-brand")) { + char *b = argv[i+1]; + CHECK_NEXT_ARG + major_brand = GF_4CC(b[0], b[1], b[2], b[3]); + open_edit = 1; + if (b[4]==':') minor_version = atoi(b+5); + i++; + } + else if (!stricmp(arg, "-ab")) { + char *b = argv[i+1]; + CHECK_NEXT_ARG + brand_add = gf_realloc(brand_add, sizeof(u32) * (nb_alt_brand_add+1)); + + brand_add[nb_alt_brand_add] = GF_4CC(b[0], b[1], b[2], b[3]); + nb_alt_brand_add++; + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-rb")) { + char *b = argv[i+1]; + CHECK_NEXT_ARG + brand_rem = gf_realloc(brand_rem, sizeof(u32) * (nb_alt_brand_rem+1)); + + brand_rem[nb_alt_brand_rem] = GF_4CC(b[0], b[1], b[2], b[3]); + nb_alt_brand_rem++; + open_edit = 1; + i++; + } +#endif + else if (!stricmp(arg, "-languages")) { + PrintLanguages(); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-h")) { + if (i+1== (u32) argc) PrintUsage(); + else if (!strcmp(argv[i+1], "general")) PrintGeneralUsage(); + else if (!strcmp(argv[i+1], "extract")) PrintExtractUsage(); + else if (!strcmp(argv[i+1], "dash")) PrintDASHUsage(); + else if (!strcmp(argv[i+1], "dump")) PrintDumpUsage(); + else if (!strcmp(argv[i+1], "import")) PrintImportUsage(); + else if (!strcmp(argv[i+1], "format")) PrintFormats(); + else if (!strcmp(argv[i+1], "hint")) PrintHintUsage(); + else if (!strcmp(argv[i+1], "encode")) PrintEncodeUsage(); + else if (!strcmp(argv[i+1], "crypt")) PrintEncryptUsage(); + else if (!strcmp(argv[i+1], "meta")) PrintMetaUsage(); + else if (!strcmp(argv[i+1], "swf")) PrintSWFUsage(); +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + else if (!strcmp(argv[i+1], "rtp")) PrintStreamerUsage(); + else if (!strcmp(argv[i+1], "live")) PrintLiveUsage (); +#endif + else if (!strcmp(argv[i+1], "all")) { + PrintGeneralUsage(); + PrintExtractUsage(); + PrintDASHUsage(); + PrintDumpUsage(); + PrintImportUsage(); + PrintFormats(); + PrintHintUsage(); + PrintEncodeUsage(); + PrintEncryptUsage(); + PrintMetaUsage(); + PrintSWFUsage(); +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + PrintStreamerUsage(); + PrintLiveUsage (); +#endif + } + else PrintUsage(); + MP4BOX_EXIT_WITH_CODE(0); + } + else if (!stricmp(arg, "-v")) verbose++; + else if (!stricmp(arg, "-tag-list")) { + fprintf(stderr, "Supported iTunes tag modifiers:\n"); + for (i=0; i= to_copy) break; + } + gf_fclose(fin); + gf_fclose(fout); + MP4BOX_EXIT_WITH_CODE(0); + } +#if !defined(GPAC_DISABLE_STREAMING) + if (grab_m2ts) { + return grab_live_m2ts(grab_m2ts, grab_ifce, inName); + } +#endif + + if (gf_logs) { + //gf_log_set_tools_levels(gf_logs); + } else { + u32 level = verbose ? GF_LOG_DEBUG : GF_LOG_INFO; + gf_log_set_tool_level(GF_LOG_CONTAINER, level); + gf_log_set_tool_level(GF_LOG_SCENE, level); + gf_log_set_tool_level(GF_LOG_PARSER, level); + gf_log_set_tool_level(GF_LOG_AUTHOR, level); + gf_log_set_tool_level(GF_LOG_CODING, level); +#ifdef GPAC_MEMORY_TRACKING + if (enable_mem_tracker) + gf_log_set_tool_level(GF_LOG_MEMORY, level); +#endif + if (quiet) { + if (quiet==2) gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_QUIET); + gf_set_progress_callback(NULL, progress_quiet); + + } + } + +#if !defined(DISABLE_CORE_TOOLS) + if (do_wget != NULL) { + e = gf_dm_wget(do_wget, inName, 0, 0, NULL); + if (e != GF_OK) { + fprintf(stderr, "Cannot retrieve %s: %s\n", do_wget, gf_error_to_string(e) ); + } + MP4BOX_EXIT_WITH_CODE(1); + } +#endif + +#ifndef GPAC_DISABLE_MPD + if (do_mpd) { + Bool remote = GF_FALSE; + char *mpd_base_url = NULL; + if (!strnicmp(inName, "http://", 7)) { +#if !defined(GPAC_DISABLE_CORE_TOOLS) + e = gf_dm_wget(inName, "tmp_main.m3u8", 0, 0, &mpd_base_url); + if (e != GF_OK) { + fprintf(stderr, "Cannot retrieve M3U8 (%s): %s\n", inName, gf_error_to_string(e)); + if (mpd_base_url) gf_free(mpd_base_url); + MP4BOX_EXIT_WITH_CODE(1); + } + remote = GF_TRUE; +#else + gf_free(mpd_base_url); + fprintf(stderr, "HTTP Downloader disabled in this build\n"); + MP4BOX_EXIT_WITH_CODE(1); +#endif + } + e = gf_m3u8_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd_base_url ? mpd_base_url : inName, (outName ? outName : inName), 0, "video/mp2t", GF_TRUE, use_url_template, NULL); + if (mpd_base_url) gf_free(mpd_base_url); + + if (remote) { + //gf_delete_file("tmp_main.m3u8"); + } + if (e != GF_OK) { + fprintf(stderr, "Error converting M3U8 (%s) to MPD (%s): %s\n", inName, outName, gf_error_to_string(e)); + MP4BOX_EXIT_WITH_CODE(1); + } else { + fprintf(stderr, "Done converting M3U8 (%s) to MPD (%s)\n", inName, outName); + MP4BOX_EXIT_WITH_CODE(0); + } + } +#endif + if (dash_duration && !nb_dash_inputs) { + dash_inputs = set_dash_input(dash_inputs, inName, &nb_dash_inputs); + } + + + if (do_saf && !encode) { + switch (get_file_type_by_ext(inName)) { + case GF_FILE_TYPE_BT_WRL_X3DV: + case GF_FILE_TYPE_XMT_X3D: + case GF_FILE_TYPE_SVG: + encode = 1; + break; + case GF_FILE_TYPE_NOT_SUPPORTED: + case GF_FILE_TYPE_ISO_MEDIA: + case GF_FILE_TYPE_SWF: + case GF_FILE_TYPE_LSR_SAF: + break; + } + } + +#ifndef GPAC_DISABLE_SCENE_DUMP + if (dump_mode == GF_SM_DUMP_SVG) { + if (strstr(inName, ".srt") || strstr(inName, ".ttxt")) import_subtitle = 2; + } +#endif + + + if (import_subtitle && !trackID) { + /* We import the subtitle file, + i.e. we parse it and store the content as samples of a 3GPP Timed Text track in an ISO file, + possibly for later export (e.g. when converting SRT to TTXT, ...) */ +#ifndef GPAC_DISABLE_MEDIA_IMPORT + GF_MediaImporter import; + /* Prepare the importer */ + file = gf_isom_open("ttxt_convert", GF_ISOM_OPEN_WRITE, NULL); + if (timescale && file) gf_isom_set_timescale(file, timescale); + + memset(&import, 0, sizeof(GF_MediaImporter)); + import.dest = file; + import.in_name = inName; + /* Start the import */ + e = gf_media_import(&import); + if (e) { + fprintf(stderr, "Error importing %s: %s\n", inName, gf_error_to_string(e)); + gf_isom_delete(file); + gf_delete_file("ttxt_convert"); + MP4BOX_EXIT_WITH_CODE(1); + } + /* Prepare the export */ + strcpy(outfile, inName); + if (strchr(outfile, '.')) { + while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0; + outfile[strlen(outfile)-1] = 0; + } +#ifndef GPAC_DISABLE_ISOM_DUMP + /* Start the export of the track #1, in the appropriate dump type, indicating it's a conversion */ + dump_timed_text_track(file, gf_isom_get_track_id(file, 1), + dump_std ? NULL : outfile, + GF_TRUE, + (import_subtitle==2) ? GF_TEXTDUMPTYPE_SVG : (dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT)); +#endif + /* Clean the importer */ + gf_isom_delete(file); + gf_delete_file("ttxt_convert"); + if (e) { + fprintf(stderr, "Error converting %s: %s\n", inName, gf_error_to_string(e)); + MP4BOX_EXIT_WITH_CODE(1); + } + MP4BOX_EXIT_WITH_CODE(0); +#else + fprintf(stderr, "Feature not supported\n"); + MP4BOX_EXIT_WITH_CODE(1); +#endif + } + +#if !defined(GPAC_DISABLE_MEDIA_IMPORT) && !defined(GPAC_DISABLE_ISOM_WRITE) + if (nb_add) { + u8 open_mode = GF_ISOM_OPEN_EDIT; + if (force_new) { + open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + } else { + FILE *test = gf_fopen(inName, "rb"); + if (!test) { + open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + if (!outName) outName = inName; + } else { + gf_fclose(test); + if (! gf_isom_probe_file(inName) ) { + open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + if (!outName) outName = inName; + } + } + } + + open_edit = 1; + file = gf_isom_open(inName, open_mode, tmpdir); + if (!file) { + fprintf(stderr, "Cannot open destination file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)) ); + MP4BOX_EXIT_WITH_CODE(1); + } + + for (i=0; i<(u32) argc; i++) { + if (!strcmp(argv[i], "-add")) { + char *src = argv[i+1]; + + e = import_file(file, src, import_flags, import_fps, agg_samples); + if (e) { + while (src) { + char *sep = strchr(src, '+'); + if (sep) { + sep[0] = 0; + } else { + break; + } + + e = import_file(file, src, import_flags, import_fps, agg_samples); + + if (sep) { + sep[0] = '+'; + src = sep+1; + } else { + src= NULL; + } + if (e) + break; + } + if (e) { + fprintf(stderr, "Error importing %s: %s\n", argv[i+1], gf_error_to_string(e)); + gf_isom_delete(file); + MP4BOX_EXIT_WITH_CODE(1); + } + } + i++; + } + } + + /*unless explicitly asked, remove all systems tracks*/ + if (!keep_sys_tracks) remove_systems_tracks(file); + needSave = 1; + } + + if (nb_cat) { + if (!file) { + u8 open_mode = GF_ISOM_OPEN_EDIT; + if (force_new) { + open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + } else { + FILE *test = gf_fopen(inName, "rb"); + if (!test) { + open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + if (!outName) outName = inName; + } + else gf_fclose(test); + } + + open_edit = 1; + file = gf_isom_open(inName, open_mode, tmpdir); + if (!file) { + fprintf(stderr, "Cannot open destination file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)) ); + MP4BOX_EXIT_WITH_CODE(1); + } + } + for (i=0; i<(u32)argc; i++) { + if (!strcmp(argv[i], "-cat") || !strcmp(argv[i], "-catx")) { + e = cat_isomedia_file(file, argv[i+1], import_flags, import_fps, agg_samples, tmpdir, force_cat, align_cat, !strcmp(argv[i], "-catx") ? GF_TRUE : GF_FALSE); + if (e) { + fprintf(stderr, "Error appending %s: %s\n", argv[i+1], gf_error_to_string(e)); + gf_isom_delete(file); + MP4BOX_EXIT_WITH_CODE(1); + } + i++; + } + } + /*unless explicitly asked, remove all systems tracks*/ + if (!keep_sys_tracks) remove_systems_tracks(file); + + needSave = 1; + if (conv_type && can_convert_to_isma(file)) conv_type = GF_ISOM_CONV_TYPE_ISMA; + } +#endif + +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT) + else if (chunk_mode) { + if (!inName) { + fprintf(stderr, "chunk encoding syntax: [-outctx outDump] -inctx inScene auFile\n"); + MP4BOX_EXIT_WITH_CODE(1); + } + e = EncodeFileChunk(inName, outName ? outName : inName, input_ctx, output_ctx, tmpdir); + if (e) fprintf(stderr, "Error encoding chunk file %s\n", gf_error_to_string(e)); + MP4BOX_EXIT_WITH_CODE( e ? 1 : 0 ); + } +#endif + else if (encode) { +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT) + FILE *logs = NULL; + if (do_log) { + char logfile[5000]; + strcpy(logfile, inName); + if (strchr(logfile, '.')) { + while (logfile[strlen(logfile)-1] != '.') logfile[strlen(logfile)-1] = 0; + logfile[strlen(logfile)-1] = 0; + } + strcat(logfile, "_enc.logs"); + logs = gf_fopen(logfile, "wt"); + } + strcpy(outfile, outName ? outName : inName); + if (strchr(outfile, '.')) { + while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0; + outfile[strlen(outfile)-1] = 0; + } + strcat(outfile, ".mp4"); + file = gf_isom_open(outfile, GF_ISOM_WRITE_EDIT, tmpdir); + opts.mediaSource = mediaSource ? mediaSource : outfile; + e = EncodeFile(inName, file, &opts, logs); + if (logs) gf_fclose(logs); + if (e) goto err_exit; + needSave = 1; + if (do_saf) { + needSave = 0; + open_edit = 0; + } +#endif + } + +#ifndef GPAC_DISABLE_ISOM_WRITE + else if (pack_file) { + char *fileName = strchr(pack_file, ':'); + if (fileName && ((fileName - pack_file)==4)) { + fileName[0] = 0; + file = package_file(fileName + 1, pack_file, tmpdir, pack_wgt); + fileName[0] = ':'; + } else { + file = package_file(pack_file, NULL, tmpdir, pack_wgt); + } + if (!outName) outName = inName; + needSave = 1; + open_edit = 1; + } +#endif + + if (dash_duration) { + Bool del_file = GF_FALSE; + char szMPD[GF_MAX_PATH], *sep; + GF_Config *dash_ctx = NULL; + u32 do_abort = 0; + gf_log_set_tool_level(GF_LOG_DASH, GF_LOG_INFO); + strcpy(outfile, outName ? outName : gf_url_get_resource_name(inName) ); + sep = strrchr(outfile, '.'); + if (sep) sep[0] = 0; + if (!outName) strcat(outfile, "_dash"); + strcpy(szMPD, outfile); + strcat(szMPD, ".mpd"); + + if ((dash_subduration>0) && (dash_duration > dash_subduration)) { + fprintf(stderr, "Warning: -subdur parameter (%g s) should be greater than segment duration (%g s), using segment duration instead\n", dash_subduration, dash_duration); + dash_subduration = dash_duration; + } + + if (dash_mode && dash_live) + fprintf(stderr, "Live DASH-ing - press 'q' to quit, 's' to save context and quit\n"); + + if (!dash_ctx_file && dash_live) { + dash_ctx = gf_cfg_new(NULL, NULL); + } else if (dash_ctx_file) { + if (force_new) + gf_delete_file(dash_ctx_file); + + dash_ctx = gf_cfg_force_new(NULL, dash_ctx_file); + } + + if (dash_profile==GF_DASH_PROFILE_UNKNOWN) + dash_profile = dash_mode ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_FULL; + + if (!dash_mode) { + time_shift_depth = 0; + mpd_update_time = 0; + } else if ((dash_profile>=GF_DASH_PROFILE_MAIN) && !use_url_template && !mpd_update_time) { + /*use a default MPD update of dash_duration sec*/ + mpd_update_time = (Double) (dash_subduration ? dash_subduration : dash_duration); + fprintf(stderr, "Using default MPD refresh of %g seconds\n", mpd_update_time); + } + + if (file && needSave) { + gf_isom_close(file); + file = NULL; + del_file = GF_TRUE; + } + while (1) { + if (do_abort>=2) { + dash_mode = GF_DASH_DYNAMIC_LAST; + } + + e = gf_dasher_segment_files(szMPD, dash_inputs, nb_dash_inputs, dash_profile, dash_title, dash_source, cprt, dash_more_info, + (const char **) mpd_base_urls, nb_mpd_base_urls, + use_url_template, segment_timeline, single_segment, single_file, bitstream_switching_mode, + seg_at_rap, dash_duration, seg_name, seg_ext, segment_marker, + interleaving_time, subsegs_per_sidx, daisy_chain_sidx, frag_at_rap, tmpdir, + dash_ctx, dash_mode, mpd_update_time, time_shift_depth, dash_subduration, min_buffer, + ast_offset_ms, dash_scale, memory_frags, initial_moof_sn, initial_tfdt, no_fragments_defaults, + pssh_in_moof, samplegroups_in_traf, single_traf_per_moof, mpd_live_duration, insert_utc, frag_real_time, dash_profile_extension); + + if (do_abort) + break; + + //this happens when reading file while writing them (local playback of the live session ...) + if (dash_live && (e==GF_IO_ERR) ) { + fprintf(stderr, "Error dashing file (%s) but continuing ...\n", gf_error_to_string(e) ); + e = GF_OK; + } + + if (e) break; + + if (dash_live) { + u32 slept = gf_sys_clock(); + u32 sleep_for = gf_dasher_next_update_time(dash_ctx, mpd_update_time); + fprintf(stderr, "Next generation scheduled in %d ms\n", sleep_for); + while (1) { + if (gf_prompt_has_input()) { + char c = (char) gf_prompt_get_char(); + if (c=='X') { + do_abort = 1; + break; + } + if (c=='q') { + do_abort = 2; + break; + } + if (c=='s') { + do_abort = 3; + break; + } + } + + if (dash_mode == GF_DASH_DYNAMIC_DEBUG) { + break; + } + if (!sleep_for) break; + + gf_sleep(10); + sleep_for = gf_dasher_next_update_time(dash_ctx, mpd_update_time); + if (sleep_for<10) { + fprintf(stderr, "Slept for %d ms before generation\n", gf_sys_clock() - slept); + break; + } + } + } else { + break; + } + } + + if (dash_ctx) { + if (do_abort==3) { + if (!dash_ctx_file) { + char szName[1024]; + fprintf(stderr, "Enter file name to save dash context:\n"); + if (scanf("%s", szName) == 1) { + gf_cfg_set_filename(dash_ctx, szName); + gf_cfg_save(dash_ctx); + } + } + } + gf_cfg_del(dash_ctx); + } + if (e) fprintf(stderr, "Error DASHing file: %s\n", gf_error_to_string(e)); + if (file) gf_isom_delete(file); + if (del_file) + gf_delete_file(inName); + + MP4BOX_EXIT_WITH_CODE( (e!=GF_OK) ? 1 : 0 ); + } + + else if (!file +#ifndef GPAC_DISABLE_MEDIA_EXPORT + && !(track_dump_type & GF_EXPORT_AVI_NATIVE) +#endif + ) { + FILE *st = gf_fopen(inName, "rb"); + Bool file_exists = 0; + if (st) { + file_exists = 1; + gf_fclose(st); + } + switch (get_file_type_by_ext(inName)) { + case 1: + file = gf_isom_open(inName, (u8) (open_edit ? GF_ISOM_OPEN_EDIT : ( ((dump_isom>0) || print_info) ? GF_ISOM_OPEN_READ_DUMP : GF_ISOM_OPEN_READ) ), tmpdir); + if (!file && (gf_isom_last_error(NULL) == GF_ISOM_INCOMPLETE_FILE) && !open_edit) { + u64 missing_bytes; + e = gf_isom_open_progressive(inName, 0, 0, &file, &missing_bytes); + fprintf(stderr, "Truncated file - missing "LLD" bytes\n", missing_bytes); + } + + if (!file) { + if (open_edit && nb_meta_act) { + file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, tmpdir); + if (!outName && file) outName = inName; + } + + if (!file) { + fprintf(stderr, "Error opening file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL))); + MP4BOX_EXIT_WITH_CODE(1); + } + } + break; + /*allowed for bt<->xmt*/ + case 2: + case 3: + /*allowed for svg->lsr**/ + case 4: + /*allowed for swf->bt, swf->xmt, swf->svg*/ + case 5: + break; + /*used for .saf / .lsr dump*/ + case 6: +#ifndef GPAC_DISABLE_SCENE_DUMP + if ((dump_mode==GF_SM_DUMP_LASER) || (dump_mode==GF_SM_DUMP_SVG)) { + break; + } +#endif + + default: + if (!open_edit && file_exists && !gf_isom_probe_file(inName) && track_dump_type) { + } +#ifndef GPAC_DISABLE_ISOM_WRITE + else if (!open_edit && file_exists /* && !gf_isom_probe_file(inName) */ +#ifndef GPAC_DISABLE_SCENE_DUMP + && dump_mode == GF_SM_DUMP_NONE +#endif + ) { + /*************************************************************************************************/ +#ifndef GPAC_DISABLE_MEDIA_IMPORT + if(dvbhdemux) + { + GF_MediaImporter import; + file = gf_isom_open("ttxt_convert", GF_ISOM_OPEN_WRITE, NULL); + memset(&import, 0, sizeof(GF_MediaImporter)); + import.dest = file; + import.in_name = inName; + import.flags = GF_IMPORT_MPE_DEMUX; + e = gf_media_import(&import); + if (e) { + fprintf(stderr, "Error importing %s: %s\n", inName, gf_error_to_string(e)); + gf_isom_delete(file); + gf_delete_file("ttxt_convert"); + MP4BOX_EXIT_WITH_CODE(1); + } + } +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ + + if (dump_m2ts) { +#ifndef GPAC_DISABLE_MPEG2TS + dump_mpeg2_ts(inName, pes_dump, program_number); +#endif + } else if (dump_timestamps) { +#ifndef GPAC_DISABLE_MPEG2TS + dump_mpeg2_ts(inName, pes_dump, program_number); +#endif + } else if (do_bin_nhml) { + nhml_bs_to_bin(inName, outName, dump_std); + } else if (do_hash) { + hash_file(inName, dump_std); + } else { +#ifndef GPAC_DISABLE_MEDIA_IMPORT + convert_file_info(inName, info_track_id); +#endif + } + MP4BOX_EXIT_WITH_CODE(0); + } +#endif /*GPAC_DISABLE_ISOM_WRITE*/ + else if (open_edit) { + file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, tmpdir); + if (!outName && file) outName = inName; + } else if (!file_exists) { + fprintf(stderr, "Error creating file %s: %s\n", inName, gf_error_to_string(GF_URL_ERROR)); + MP4BOX_EXIT_WITH_CODE(1); + } else { + fprintf(stderr, "Cannot open %s - extension not supported\n", inName); + MP4BOX_EXIT_WITH_CODE(1); + } + } + } + + if (file && keep_utc && open_edit) { + gf_isom_keep_utc_times(file, 1); + } + + strcpy(outfile, outName ? outName : inName); + if (strrchr(outfile, '.')) { + char *szExt = strrchr(outfile, '.'); + + /*turn on 3GP saving*/ + if (!stricmp(szExt, ".3gp") || !stricmp(szExt, ".3gpp") || !stricmp(szExt, ".3g2")) + conv_type = GF_ISOM_CONV_TYPE_3GPP; + else if (!stricmp(szExt, ".m4a") || !stricmp(szExt, ".m4v")) + conv_type = GF_ISOM_CONV_TYPE_IPOD; + else if (!stricmp(szExt, ".psp")) + conv_type = GF_ISOM_CONV_TYPE_PSP; + + while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0; + outfile[strlen(outfile)-1] = 0; + } + +#ifndef GPAC_DISABLE_MEDIA_EXPORT + if (track_dump_type & GF_EXPORT_AVI_NATIVE) { + char szFile[1024]; + GF_MediaExporter mdump; + memset(&mdump, 0, sizeof(mdump)); + mdump.in_name = inName; + mdump.flags = GF_EXPORT_AVI_NATIVE; + mdump.trackID = trackID; + if (dump_std) { + mdump.out_name = "std"; + } else if (outName) { + mdump.out_name = outName; + } else if (trackID>2) { + sprintf(szFile, "%s_audio%d", outfile, trackID-1); + mdump.out_name = szFile; + } else { + sprintf(szFile, "%s_%s", outfile, (trackID==1) ? "video" : "audio"); + mdump.out_name = szFile; + } + + e = gf_media_export(&mdump); + if (e) goto err_exit; + MP4BOX_EXIT_WITH_CODE(0); + } + if (!open_edit && !gf_isom_probe_file(inName) && track_dump_type) { + GF_MediaExporter mdump; + char szFile[1024]; + for (i=0; iact_type != TRAC_ACTION_RAW_EXTRACT) continue; + memset(&mdump, 0, sizeof(mdump)); + mdump.in_name = inName; + mdump.flags = tka->dump_type; + mdump.trackID = tka->trackID; + mdump.sample_num = raw_sample_num; + if (outName) { + mdump.out_name = outName; + mdump.flags |= GF_EXPORT_MERGE; + } else if (nb_track_act>1) { + sprintf(szFile, "%s_track%d", outfile, mdump.trackID); + mdump.out_name = szFile; + } else { + mdump.out_name = outfile; + } + e = gf_media_export(&mdump); + if (e) goto err_exit; + } + MP4BOX_EXIT_WITH_CODE(0); + } + +#endif /*GPAC_DISABLE_MEDIA_EXPORT*/ + +#ifndef GPAC_DISABLE_SCENE_DUMP + if (dump_mode != GF_SM_DUMP_NONE) { + e = dump_file_text(inName, dump_std ? NULL : outfile, dump_mode, do_log); + if (e) goto err_exit; + } +#endif + +#ifndef GPAC_DISABLE_SCENE_STATS + if (stat_level) dump_scene_stats(inName, dump_std ? NULL : outfile, stat_level); +#endif + +#ifndef GPAC_DISABLE_ISOM_HINTING + if (!HintIt && print_sdp) DumpSDP(file, dump_std ? NULL : outfile); +#endif + if (print_info) { + if (!file) { + fprintf(stderr, "Cannot print info on a non ISOM file (%s)\n", inName); + } else { + if (info_track_id) DumpTrackInfo(file, info_track_id, 1); + else DumpMovieInfo(file); + } + } +#ifndef GPAC_DISABLE_ISOM_DUMP + if (dump_isom) dump_isom_xml(file, dump_std ? NULL : outfile); + if (dump_cr) dump_file_ismacryp(file, dump_std ? NULL : outfile); + if ((dump_ttxt || dump_srt) && trackID) dump_timed_text_track(file, trackID, dump_std ? NULL : outfile, 0, dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT); +#ifndef GPAC_DISABLE_ISOM_HINTING + if (dump_rtp) dump_file_rtp(file, dump_std ? NULL : outfile); +#endif +#endif + + if (dump_timestamps) dump_file_timestamps(file, dump_std ? NULL : outfile); + if (dump_nal) dump_file_nal(file, dump_nal, dump_std ? NULL : outfile); + + if (do_hash) { + e = hash_file(inName, dump_std); + if (e) goto err_exit; + } + if (do_bin_nhml) { + e = nhml_bs_to_bin(inName, outName, dump_std); + if (e) goto err_exit; + } + + if (dump_cart) dump_cover_art(file, outfile); + if (dump_chap) dump_chapters(file, outfile, (dump_chap==2) ? 1 : 0); + if (dump_udta_type) dump_udta(file, outfile, dump_udta_type, dump_udta_track); + + if (dump_iod) { + GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)gf_isom_get_root_od(file); + if (!iod) { + fprintf(stderr, "File %s has no IOD", inName); + } else { + char szName[GF_MAX_PATH]; + FILE *iodf; + GF_BitStream *bs = NULL; + + sprintf(szName, "%s.iod", outfile); + iodf = gf_fopen(szName, "wb"); + if (!iodf) { + fprintf(stderr, "Cannot open destination %s\n", szName); + } else { + char *desc; + u32 size; + bs = gf_bs_from_file(iodf, GF_BITSTREAM_WRITE); + if (gf_odf_desc_write((GF_Descriptor *)iod, &desc, &size)==GF_OK) { + gf_fwrite(desc, 1, size, iodf); + gf_free(desc); + } else { + fprintf(stderr, "Error writing IOD %s\n", szName); + } + gf_fclose(iodf); + } + gf_free(bs); + } + } + +#if !(definedGPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) + if (split_duration || split_size) { + split_isomedia_file(file, split_duration, split_size, inName, interleaving_time, split_start, adjust_split_end, outName, tmpdir); + /*never save file when splitting is desired*/ + open_edit = 0; + needSave = 0; + } +#endif + +#ifndef GPAC_DISABLE_MEDIA_EXPORT + if (track_dump_type) { + char szFile[1024]; + GF_MediaExporter mdump; + for (i=0; iact_type != TRAC_ACTION_RAW_EXTRACT) continue; + memset(&mdump, 0, sizeof(mdump)); + mdump.file = file; + mdump.flags = tka->dump_type; + mdump.trackID = tka->trackID; + mdump.sample_num = raw_sample_num; + if (tka->out_name) { + mdump.out_name = tka->out_name; + } else if (outName) { + mdump.out_name = outName; + mdump.flags |= GF_EXPORT_MERGE; + } else { + sprintf(szFile, "%s_track%d", outfile, mdump.trackID); + mdump.out_name = szFile; + } + if (tka->trackID==(u32) -1) { + u32 j; + for (j=0; jtrackID) tk = gf_isom_get_track_by_id(file, meta->trackID); + + switch (meta->act_type) { +#ifndef GPAC_DISABLE_ISOM_WRITE + case META_ACTION_SET_TYPE: + /*note: we don't handle file brand modification, this is an author stuff and cannot be guessed from meta type*/ + e = gf_isom_set_meta_type(file, meta->root_meta, tk, meta->meta_4cc); + gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO2, 1); + needSave = 1; + break; + case META_ACTION_ADD_ITEM: + self_ref = !stricmp(meta->szPath, "NULL") || !stricmp(meta->szPath, "this") || !stricmp(meta->szPath, "self"); + e = gf_isom_add_meta_item(file, meta->root_meta, tk, self_ref, self_ref ? NULL : meta->szPath, + strlen(meta->szName) ? meta->szName : NULL, + meta->item_id, + strlen(meta->mime_type) ? meta->mime_type : NULL, + strlen(meta->enc_type) ? meta->enc_type : NULL, + meta->use_dref ? meta->szPath : NULL, NULL); + needSave = 1; + break; + case META_ACTION_REM_ITEM: + e = gf_isom_remove_meta_item(file, meta->root_meta, tk, meta->item_id); + needSave = 1; + break; + case META_ACTION_SET_PRIMARY_ITEM: + e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id); + needSave = 1; + break; + case META_ACTION_SET_XML: + case META_ACTION_SET_BINARY_XML: + e = gf_isom_set_meta_xml(file, meta->root_meta, tk, meta->szPath, (meta->act_type==META_ACTION_SET_BINARY_XML) ? 1 : 0); + needSave = 1; + break; + case META_ACTION_REM_XML: + if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) { + e = gf_isom_remove_meta_xml(file, meta->root_meta, tk); + needSave = 1; + } else { + fprintf(stderr, "No meta box in input file\n"); + } + break; + case META_ACTION_DUMP_XML: + if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) { + e = gf_isom_extract_meta_item(file, meta->root_meta, tk, meta->item_id, strlen(meta->szPath) ? meta->szPath : NULL); + } else { + fprintf(stderr, "No meta box in input file\n"); + } + break; +#endif + case META_ACTION_DUMP_ITEM: + if (gf_isom_has_meta_xml(file, meta->root_meta, tk)) { + e = gf_isom_extract_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL); + } else { + fprintf(stderr, "No meta box in input file\n"); + } + break; + default: + break; + } + if (e) goto err_exit; + } + if (!open_edit && !needSave) { + if (file) gf_isom_delete(file); + MP4BOX_EXIT_WITH_CODE(0); + } + +#ifndef GPAC_DISABLE_ISOM_WRITE + for (i=0; i0) { + u32 tk, k; + for (k=0; k<(u32) count; k++) { + gf_isom_get_reference(file, j+1, GF_4CC('c','h','a','p'), k+1, &tk); + if (tk==i+1) { + is_chap = 1; + break; + } + } + if (is_chap) break; + } + if (is_chap) break; + } + /*this is a subtitle track*/ + if (!is_chap) + gf_isom_set_media_type(file, i+1, GF_ISOM_MEDIA_SUBT); + } + break; + } + } + gf_isom_set_brand_info(file, major_brand, 1); + gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_MP42, 1); + needSave = 1; + } + +#ifndef GPAC_DISABLE_MCRYPT + if (crypt) { + if (!drm_file) { + fprintf(stderr, "Missing DRM file location - usage '-%s drm_file input_file\n", (crypt==1) ? "crypt" : "decrypt"); + e = GF_BAD_PARAM; + goto err_exit; + } + if (crypt == 1) { + e = gf_crypt_file(file, drm_file); + } else if (crypt ==2) { + e = gf_decrypt_file(file, drm_file); + } + if (e) goto err_exit; + needSave = 1; + } +#endif /*GPAC_DISABLE_MCRYPT*/ + } else if (outName) { + strcpy(outfile, outName); + } + + + for (i=0; itrackID ? gf_isom_get_track_by_id(file, tka->trackID) : 0; + u32 timescale = gf_isom_get_timescale(file); + switch (tka->act_type) { + case TRAC_ACTION_REM_TRACK: + e = gf_isom_remove_track(file, track); + if (e) { + fprintf(stderr, "Error Removing track ID %d: %s\n", tka->trackID, gf_error_to_string(e)); + } else { + fprintf(stderr, "Removing track ID %d\n", tka->trackID); + } + needSave = 1; + break; + case TRAC_ACTION_SET_LANGUAGE: + for (i=0; ilang); + if (e) goto err_exit; + needSave = 1; + } + needSave = 1; + break; + case TRAC_ACTION_SET_KIND: + for (i=0; ikind_scheme, tka->kind_value); + if (e) goto err_exit; + needSave = 1; + } + needSave = 1; + break; + case TRAC_ACTION_REM_KIND: + for (i=0; ikind_scheme, tka->kind_value); + if (e) goto err_exit; + needSave = 1; + } + needSave = 1; + break; + case TRAC_ACTION_SET_DELAY: + if (tka->delay_ms) { + u64 tk_dur; + + gf_isom_remove_edit_segments(file, track); + tk_dur = gf_isom_get_track_duration(file, track); + if (gf_isom_get_edit_segment_count(file, track)) + needSave = 1; + if (tka->delay_ms>0) { + gf_isom_append_edit_segment(file, track, (timescale*tka->delay_ms)/1000, 0, GF_ISOM_EDIT_EMPTY); + gf_isom_append_edit_segment(file, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL); + needSave = 1; + } else { + u64 to_skip = (timescale*(-tka->delay_ms))/1000; + if (to_skipdelay_ms)*gf_isom_get_media_timescale(file, track) / 1000; + gf_isom_append_edit_segment(file, track, tk_dur-to_skip, media_time, GF_ISOM_EDIT_NORMAL); + needSave = 1; + } else { + fprintf(stderr, "Warning: request negative delay longer than track duration - ignoring\n"); + } + } + } else if (gf_isom_get_edit_segment_count(file, track)) { + gf_isom_remove_edit_segments(file, track); + needSave = 1; + } + break; + case TRAC_ACTION_SET_KMS_URI: + for (i=0; ikms); + if (e) goto err_exit; + needSave = 1; + } + break; + case TRAC_ACTION_SET_ID: + if (track) { + u32 newTrack; + newTrack = gf_isom_get_track_by_id(file, tka->newTrackID); + if (newTrack != 0) { + fprintf(stderr, "Error: Cannot set track id with value %d because a track already exists - ignoring", tka->newTrackID); + } else { + e = gf_isom_set_track_id(file, track, tka->newTrackID); + needSave = 1; + } + } else { + fprintf(stderr, "Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID); + } + break; + case TRAC_ACTION_SET_PAR: + e = gf_media_change_par(file, track, tka->par_num, tka->par_den); + needSave = 1; + break; + case TRAC_ACTION_SET_HANDLER_NAME: + e = gf_isom_set_handler_name(file, track, tka->hdl_name); + needSave = 1; + break; + case TRAC_ACTION_ENABLE: + if (!gf_isom_is_track_enabled(file, track)) { + e = gf_isom_set_track_enabled(file, track, 1); + needSave = 1; + } + break; + case TRAC_ACTION_DISABLE: + if (gf_isom_is_track_enabled(file, track)) { + e = gf_isom_set_track_enabled(file, track, 0); + needSave = 1; + } + break; + case TRAC_ACTION_REFERENCE: + e = gf_isom_set_track_reference(file, track, GF_4CC(tka->lang[0], tka->lang[1], tka->lang[2], tka->lang[3]), (u32) tka->delay_ms); + needSave = 1; + break; + case TRAC_ACTION_REM_NON_RAP: + fprintf(stderr, "Removing non-rap samples from track %d\n", tka->trackID); + e = gf_media_remove_non_rap(file, track); + needSave = 1; + break; + case TRAC_ACTION_SET_UDTA: + set_file_udta(file, track, tka->udta_type, tka->src_name, tka->sample_num ? GF_TRUE : GF_FALSE); + needSave = 1; + break; + default: + break; + } + if (e) goto err_exit; + } + + if (itunes_tags) { + char *tags = itunes_tags; + + while (tags) { + char *val; + char *sep = strchr(tags, ':'); + u32 tlen, itag = 0; + if (sep) { + while (sep) { + for (itag=0; itag>8; + _t[5]=t; + _t[4]=t>>8; + } + else if (sscanf(val, "%u", &n) == 1) { + _t[3]=n; + _t[2]=n>>8; + } + else tlen = 0; + if (tlen) gf_isom_apple_set_tag(file, itag, _t, tlen); + } + break; + case GF_ISOM_ITUNE_GAPLESS: + case GF_ISOM_ITUNE_COMPILATION: + { + char _t[1]; + if (val && !stricmp(val, "yes")) _t[0] = 1; + else _t[0] = 0; + gf_isom_apple_set_tag(file, itag, _t, 1); + } + break; + default: + gf_isom_apple_set_tag(file, itag, val, tlen); + break; + } + needSave = 1; + + if (sep) { + sep[0] = ':'; + tags = sep+1; + } else { + tags = NULL; + } + } + } + + if (movie_time) { + gf_isom_set_creation_time(file, movie_time); + for (i=0; i +#include +#include "stdlib.h" +#include "stdio.h" +#include "string.h" + + +#define jniTAG "WRAPPER_JNI" + +#define jniLOGV(X) __android_log_print(ANDROID_LOG_VERBOSE, jniTAG, X) +#define jniLOGI(X) __android_log_print(ANDROID_LOG_INFO, jniTAG, X) +#define jniLOGE(X) __android_log_print(ANDROID_LOG_ERROR, jniTAG, X) + +/*#define CAST_HANDLE(wr) jclass c = env->GetObjectClass(obj);\ + if (!c) return;\ + jfieldID fid = env->GetFieldID(c, "handle", "J");\ + if (!fid){\ + __android_log_print(ANDROID_LOG_ERROR, jniTAG, "No Field ID, ERROR");\ + return;\ + }\ + jlong h = env->GetLongField(obj, fid); + //CNativeWrapper* wr = (CNativeWrapper*) h;*/ + +char ** ConvertCommandLine( const char* sCommand, int* iNbArg ); + +JNIEXPORT void JNICALL Java_com_enst_mp4box_mp4terminal_run(JNIEnv * env, jobject obj, jstring sCommand) +{ + //CAST_HANDLE(wr); + jniLOGV("mp4terminal::start"); + /*if (!wr) + { + jniLOGV("mp4terminal::end : aborted"); + return; + }*/ + jboolean isCopy; + const char * sOriginalCommand = (*env)->GetStringUTFChars(env, sCommand, &isCopy); + + jniLOGV("mp4terminal::command get back ok"); + jniLOGV(sOriginalCommand); + + int iNbArg = 0; + + int i = 0; + char** sConvertedCommandLine; + sConvertedCommandLine = ConvertCommandLine( sOriginalCommand, &i ); + + jniLOGV("Convert command line done"); + FILE* ferr = freopen( "/mnt/sdcard/stderrout.txt", "w", stderr ); + + FILE* fout = freopen( "/mnt/sdcard/stdout.txt", "w", stdout ); + + mp4boxMain(i, sConvertedCommandLine); + + (*env)->ReleaseStringUTFChars(env, sCommand, sOriginalCommand); + jniLOGV("mp4terminal::end"); + gf_fclose(ferr); + gf_fclose(fout); +} + +char ** ConvertCommandLine( const char* sCommand, int* iNbArg ) +{ + int iLength = strlen( sCommand ); + int iArgNumber = 1; + int i = 0; + char** pReturn; + int iPreviousPos = 0; + int k = 1;//begin at character position 1 as the 0 position will be held by the process name , i.e. mp4box + int l = 0; + + for ( i = 0; i < iLength ; i++ ) + { + if( sCommand[i] == ' ' ) + { + iArgNumber++; + } + } + iArgNumber++;; // last argument will not be detected as it is not followed by a space character + pReturn = (char**)malloc(sizeof(char*)*iArgNumber); + pReturn[0] = (char*)malloc(sizeof( char) * ( 7 )); + strcpy( pReturn[0], "MP4Box" );//just a place holder , will never be read. + pReturn[0][6] = '\0'; + + for ( l = 0; l <= iLength ; l++ ) + { + if( sCommand[l] == ' ' || l == ( iLength ) ) + { + pReturn[k] = (char*)malloc(sizeof( char) * ( l - iPreviousPos + 1)); + strncpy( pReturn[k], sCommand + iPreviousPos, l - iPreviousPos ); + pReturn[k][l-iPreviousPos] = '\0'; + iPreviousPos = l + 1; + k++; + } + } + *iNbArg = iArgNumber; + return pReturn; +} +#ifdef __cplusplus +} +#endif + diff --git a/applications/mp4client/Makefile b/applications/mp4client/Makefile new file mode 100644 index 0000000..6aff667 --- /dev/null +++ b/applications/mp4client/Makefile @@ -0,0 +1,64 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/applications/mp4client + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" -I../../ + +LINKLIBS=$(GPAC_SH_FLAGS) + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +ifeq ($(GPACREADONLY), yes) +CFLAGS+=-DGPAC_READ_ONLY +endif + +#common obj +OBJS= main.o extract.o + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=MP4Client$(EXE) +else +EXT= +PROG=MP4Client +endif + +ifeq ($(CONFIG_DARWIN),yes) +OBJS+= carbon_events.o +LDFLAGS += -framework Carbon +endif + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +MP4Client$(EXE): $(OBJS) + $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(LINKLIBS) + +clean: + rm -f $(OBJS) ../../bin/gcc/$(PROG) + +install: clean + install -m 755 $(INSTFLAGS) ../../bin/gcc/MP4Client "$(DESTDIR)$(prefix)/bin" + +uninstall: + rm -rf $(DESTDIR)$(prefix)/bin/MP4Client + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/mp4client/carbon_events.c b/applications/mp4client/carbon_events.c new file mode 100644 index 0000000..d4226bb --- /dev/null +++ b/applications/mp4client/carbon_events.c @@ -0,0 +1,109 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2005-2012 + * All rights reserved + * + * This file is part of GPAC / command-line client + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#if defined(__DARWIN__) || defined(__APPLE__) +#include +#endif + + +void gf_sys_set_args(int argc, const char **argv); +void send_open_url(const char *url); + +void RunApplicationEventLoop(void); +void QuitApplicationEventLoop(void); + +char *my_argv[2]; + +static int main_evt_loop_run = 1; + +static AEEventHandlerUPP open_app_UPP, open_doc_UPP; + +static pascal OSErr ae_open_app (const AppleEvent *ae_event, AppleEvent *ae_reply, long ae_ref_count) +{ + if (main_evt_loop_run) { + QuitApplicationEventLoop(); + main_evt_loop_run = 0; + } + return (noErr); +} + +static pascal OSErr ae_open_doc (const AppleEvent *ae_event, AppleEvent *ae_reply, long ae_ref_count) +{ + OSErr err; + FSRef ref; + AEDescList docList; + long count; + + err = AEGetParamDesc(ae_event, keyDirectObject, typeAEList, &docList); + if (err) + return (noErr); + + err = AECountItems(&docList, &count); + if (err == noErr) { + err = AEGetNthPtr(&docList, 1, typeFSRef, NULL, NULL, &ref, sizeof(FSRef), NULL); + if (err == noErr) { + char path[4096]; + FSRefMakePath(&ref, (UInt8 *) path, 4096); + if (main_evt_loop_run) { + my_argv[1] = strdup(path); + gf_sys_set_args(2, (const char **) my_argv); + } else { + send_open_url(path); + } + } + } + err = AEDisposeDesc(&docList); + + if (main_evt_loop_run) { + QuitApplicationEventLoop(); + main_evt_loop_run = 0; + } + return (noErr); +} + +void carbon_init () +{ + my_argv[0] = "GPAC"; + my_argv[1] = NULL; + + open_app_UPP = NewAEEventHandlerUPP(ae_open_app); + AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, open_app_UPP, 0L, false); + open_doc_UPP = NewAEEventHandlerUPP(ae_open_doc); + AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, open_doc_UPP, 0L, false); + + main_evt_loop_run = 1; + RunApplicationEventLoop(); +} + +void carbon_uninit() +{ + + DisposeAEEventHandlerUPP(open_app_UPP); + DisposeAEEventHandlerUPP(open_doc_UPP); + + if (my_argv[1]) free(my_argv[1]); +} + + diff --git a/applications/mp4client/extract.c b/applications/mp4client/extract.c new file mode 100644 index 0000000..20970df --- /dev/null +++ b/applications/mp4client/extract.c @@ -0,0 +1,962 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2005-2012 + * All rights reserved + * + * This file is part of GPAC / command-line client + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include + +#ifdef WIN32 +#include +#else +typedef struct tagBITMAPFILEHEADER +{ + u16 bfType; + u32 bfSize; + u16 bfReserved1; + u16 bfReserved2; + u32 bfOffBits; +} BITMAPFILEHEADER; + +typedef struct tagBITMAPINFOHEADER { + u32 biSize; + s32 biWidth; + s32 biHeight; + u16 biPlanes; + u16 biBitCount; + u32 biCompression; + u32 biSizeImage; + s32 biXPelsPerMeter; + s32 biYPelsPerMeter; + u32 biClrUsed; + u32 biClrImportant; +} BITMAPINFOHEADER; + +#define BI_RGB 0L + +#endif + + +#include +#include +#include + + +enum +{ + DUMP_NONE = 0, + DUMP_AVI = 1, + DUMP_BMP = 2, + DUMP_PNG = 3, + DUMP_RAW = 4, + DUMP_SHA1 = 5, + + //DuMP flags + DUMP_DEPTH_ONLY = 1<<16, + DUMP_RGB_DEPTH = 1<<17, + DUMP_RGB_DEPTH_SHAPE = 1<<18 +}; + + +extern Bool is_connected; +extern GF_Terminal *term; +extern u64 Duration; +extern GF_Err last_error; +extern Bool no_prog; + + +static GFINLINE u8 colmask(s32 a, s32 n) +{ + s32 mask = (1 << n) - 1; + return (u8) (a & (0xff & ~mask)) | ((-((a >> n) & 1)) & mask); +} + +static u32 put_pixel(FILE *fout, u32 type, u32 pf, char *ptr) +{ + u16 col; + switch (pf) { + case GF_PIXEL_RGB_32: + case GF_PIXEL_ARGB: + fputc(ptr[0], fout); + fputc(ptr[1], fout); + fputc(ptr[2], fout); + return 4; + + case GF_PIXEL_BGR_32: + case GF_PIXEL_RGBA: + fputc(ptr[2], fout); + fputc(ptr[1], fout); + fputc(ptr[0], fout); + return 4; + + case GF_PIXEL_RGB_24: + fputc(ptr[2], fout); + fputc(ptr[1], fout); + fputc(ptr[0], fout); + return 3; + + case GF_PIXEL_BGR_24: + fputc(ptr[2], fout); + fputc(ptr[1], fout); + fputc(ptr[0], fout); + return 3; + case GF_PIXEL_RGB_565: + col = * (u16 *)ptr; + fputc(colmask(col << 3, 3), fout); + fputc(colmask(col >> (5 - 2), 2), fout); + fputc(colmask(col >> (11 - 3), 3), fout); + return 2; + + case GF_PIXEL_RGB_555: + col = * (u16 *)ptr; + fputc(colmask(col << 3, 3), fout); + fputc(colmask(col >> (5 - 3), 3), fout); + fputc(colmask(col >> (10 - 3), 3), fout); + return 2; + /* this is used to write the byte depthbuffer in greyscale when dumping depth*/ + case GF_PIXEL_GREYSCALE: + /* bmp always needs 3 pixels */ + fputc(ptr[0], fout); + fputc(ptr[0], fout); + fputc(ptr[0], fout); + /* if printing the characters corresponding to the float depth buffer: */ + /* + { + u32 i=0; + while (ptr[i]!='\0') { + fputc(ptr[i], fout); + i++; + } + fputc('\b', fout); + } + */ + return 1; + + + case 0: + fputc(ptr[0], fout); + return 1; + } + return 0; +} + +void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) +{ + char str[GF_MAX_PATH]; + BITMAPFILEHEADER fh; + BITMAPINFOHEADER fi; + FILE *fout; + u32 j, i; + char *ptr; + + if (fb->pixel_format==GF_PIXEL_GREYSCALE) sprintf(str, "%s_%d_depth.bmp", rad_name, img_num); + else sprintf(str, "%s_%d.bmp", rad_name, img_num); + + fout = gf_fopen(str, "wb"); + if (!fout) return; + + memset(&fh, 0, sizeof(fh)); + fh.bfType = 19778; + fh.bfOffBits = 14 + 40; + + memset(&fi, 0, sizeof(char)*40); + fi.biSize = sizeof(char)*40; + fi.biWidth = fb->width; + fi.biHeight = fb->height; + fi.biPlanes = 1; + if (fb->pixel_format==GF_PIXEL_GREYSCALE) fi.biBitCount = 24; + else fi.biBitCount = 24; + fi.biCompression = BI_RGB; + fi.biSizeImage = fb->width * fb->height * 3; + + /*NOT ALIGNED!!*/ + gf_fwrite(&fh.bfType, 2, 1, fout); + gf_fwrite(&fh.bfSize, 4, 1, fout); + gf_fwrite(&fh.bfReserved1, 2, 1, fout); + gf_fwrite(&fh.bfReserved2, 2, 1, fout); + gf_fwrite(&fh.bfOffBits, 4, 1, fout); + + gf_fwrite(&fi, 1, 40, fout); + for (j=fb->height; j>0; j--) { + ptr = fb->video_buffer + (j-1)*fb->pitch_y; + for (i=0; iwidth; i++) { + u32 res = put_pixel(fout, 0, fb->pixel_format, ptr); + assert(res); + ptr += res; + } + } + gf_fclose(fout); +} + +#include + +void write_png(GF_VideoSurface *fb, char *rad_name, u32 img_num) +{ +#ifndef GPAC_DISABLE_AV_PARSERS + char str[GF_MAX_PATH]; + FILE *fout; + u32 dst_size; + char *dst; + char *prev = strrchr(rad_name, '.'); + if (prev) prev[0] = '\0'; + sprintf(str, "%s_%d.png", rad_name, img_num); + if (prev) prev[0] = '.'; + + switch (fb->pixel_format) { + case GF_PIXEL_ARGB: + case GF_PIXEL_RGBA: + dst_size = fb->width*fb->height*4; + break; + default: + dst_size = fb->width*fb->height*3; + break; + } + dst = (char*)gf_malloc(sizeof(char)*dst_size); + + + fout = gf_fopen(str, "wb"); + if (fout) { + GF_Err e = gf_img_png_enc(fb->video_buffer, fb->width, fb->height, fb->pitch_y, fb->pixel_format, dst, &dst_size); + if (!e) { + gf_fwrite(dst, dst_size, 1, fout); + gf_fclose(fout); + } + } + + gf_free(dst); +#endif //GPAC_DISABLE_AV_PARSERS +} + + + +/*writes onto a file the content of the framebuffer in *fb interpreted as the byte depthbuffer */ +/*it's also possible to write a float depthbuffer by passing the floats to strings and writing chars in putpixel - see comments*/ +void write_depthfile(GF_VideoSurface *fb, char *rad_name, u32 img_num) +{ + FILE *fout; + u32 i, j; + unsigned char *depth; + + depth = (unsigned char *) fb->video_buffer; + + fout = gf_fopen("dump_depth", "wb"); + if (!fout) return; + for (j=0; jheight; j++) { + for (i=0; iwidth; i++) { + +#ifdef GPAC_USE_TINYGL + fputc(depth[2*i+j*fb->width*sizeof(unsigned short)], fout); + fputc(depth[2*i+j*fb->width*sizeof(unsigned short) + 1], fout); +#else + fputc(depth[i+j*fb->width], fout); +#endif + } + } + gf_fclose(fout); +} + +void write_texture_file(GF_VideoSurface *fb, char *rad_name, u32 img_num, u32 dump_mode_flags) +{ + + FILE *fout; + u32 i, j; + unsigned char *buf; + + buf = (unsigned char *) fb->video_buffer; + + if (dump_mode_flags & DUMP_RGB_DEPTH_SHAPE) fout = gf_fopen("dump_rgbds", "wb"); + else if (dump_mode_flags & DUMP_RGB_DEPTH) fout = gf_fopen("dump_rgbd", "wb"); + else return; + + if (!fout) return; + for (j=0; jheight; j++) { + for (i=0; iwidth*4; i++) { + fputc(buf[i+j*fb->pitch_y], fout); + } + } + gf_fclose(fout); +} + + +void write_raw(GF_VideoSurface *fb, char *rad_name, u32 img_num) +{ + u32 j, i; + char *ptr, *prev; + char str[GF_MAX_PATH]; + FILE *fout; + prev = strrchr(rad_name, '.'); + if (prev) prev[0] = '\0'; + if (img_num<10) { + sprintf(str, "%s_00%d.raw", rad_name, img_num); + } else if (img_num<100) { + sprintf(str, "%s_0%d.raw", rad_name, img_num); + } else { + sprintf(str, "%s_%d.raw", rad_name, img_num); + } + + fout = gf_fopen(str, "wb"); + if (!fout) return; + + + for (j=0; jheight; j++) { + ptr = fb->video_buffer + j*fb->pitch_y; + for (i=0; iwidth; i++) { + u32 res = put_pixel(fout, 0, fb->pixel_format, ptr); + assert(res); + ptr += res; + } + } + gf_fclose(fout); +} + +void write_hash(FILE *sha_out, char *buf, u32 size) +{ + u8 hash[20]; + gf_sha1_csum((u8 *)buf, size, hash); + fwrite(hash, 1, 20, sha_out); +} + + +/* creates a .bmp format greyscale image of the byte depthbuffer and a binary with only the content of the depthbuffer */ +void dump_depth (GF_Terminal *term, char *rad_name, u32 dump_mode_flags, u32 frameNum, char *conv_buf, void *avi_out, FILE *sha_out) +{ + GF_Err e; + u32 i, k; + + GF_VideoSurface fb; + u32 dump_mode = dump_mode_flags & 0x0000FFFF; + + /*lock it*/ + e = gf_sc_get_screen_buffer(term->compositor, &fb, 1); + if (e) fprintf(stderr, "Error grabbing depth buffer: %s\n", gf_error_to_string(e)); + else fprintf(stderr, "OK\n"); + /*export frame*/ + switch (dump_mode) { + case DUMP_AVI: + /*reverse frame*/ + for (k=0; k> 8/*(11 - 3)*/, 3); + dst[1] = colmask(src_16 >> 3/*(5 - 2)*/, 2); + dst[0] = colmask(src_16 << 3, 3); + src+=2; + break; + case GF_PIXEL_RGB_555: + src_16 = * (u16 *)src; + dst[2] = colmask(src_16 >> 7/*(10 - 3)*/, 3); + dst[1] = colmask(src_16 >> 2/*(5 - 3)*/, 3); + dst[0] = colmask(src_16 << 3, 3); + src+=2; + break; + /*for depth .avi*/ + case GF_PIXEL_GREYSCALE: + dst[0] = src[0]; + dst[1] = src[0]; + dst[2] = src[0]; + src+=1; + break; + } + dst += 3; + } + } +#ifndef GPAC_DISABLE_AVILIB + if (avi_out) { + if (AVI_write_frame(avi_out, conv_buf, fb.height*fb.width*3, 1) <0) + fprintf(stderr, "Error writing frame\n"); + } else +#endif + if (sha_out) { + write_hash(sha_out, conv_buf, fb.height*fb.width*3); + } + + /*in -depth -avi mode, do not release it yet*/ + if (dump_mode_flags & DUMP_DEPTH_ONLY) return; + break; + case DUMP_BMP: + write_bmp(&fb, rad_name, frameNum); + break; + case DUMP_PNG: + write_png(&fb, rad_name, frameNum); + break; + case DUMP_RAW: + write_raw(&fb, rad_name, frameNum); + break; + default: + write_depthfile(&fb, rad_name, frameNum); + break; + } + /*unlock it*/ + gf_sc_release_screen_buffer(term->compositor, &fb); +} + +void dump_frame(GF_Terminal *term, char *rad_name, u32 dump_mode_flags, u32 frameNum, char *conv_buf, void *avi_out, FILE *sha_out) +{ + GF_Err e = GF_OK; + u32 i, k, out_size; + GF_VideoSurface fb; + + u32 dump_mode = dump_mode_flags & 0x0000FFFF; + u32 depth_dump_mode = 0; + + if (dump_mode_flags & DUMP_RGB_DEPTH_SHAPE) depth_dump_mode = 3; + else if (dump_mode_flags & DUMP_RGB_DEPTH) depth_dump_mode = 2; + else if (dump_mode_flags & DUMP_DEPTH_ONLY) depth_dump_mode = 1; + + /*lock it*/ + e = gf_sc_get_screen_buffer(term->compositor, &fb, depth_dump_mode); + if (e) fprintf(stderr, "Error grabbing frame buffer: %s\n", gf_error_to_string(e)); + + /*export frame*/ + switch (dump_mode) { + case DUMP_AVI: + case DUMP_SHA1: + /*reverse frame*/ + for (k=0; k> 8/*(11 - 3)*/, 3); + dst[1] = colmask(src_16 >> 3/*(5 - 2)*/, 2); + dst[0] = colmask(src_16 << 3, 3); + src+=2; + dst+=3; + } + break; + case GF_PIXEL_RGB_555: + for (i=0; i> 7/*(10 - 3)*/, 3); + dst[1] = colmask(src_16 >> 2/*(5 - 3)*/, 3); + dst[0] = colmask(src_16 << 3, 3); + src+=2; + dst +=3; + } + break; + } + } + if (dump_mode_flags & (DUMP_RGB_DEPTH | DUMP_RGB_DEPTH_SHAPE)) { + out_size = fb.height*fb.width*4; + } else { + out_size = fb.height*fb.width*3; + } +#ifndef GPAC_DISABLE_AVILIB + if (avi_out) { + if (AVI_write_frame(avi_out, conv_buf, out_size, 1) <0) + fprintf(stderr, "Error writing frame\n"); + } else +#endif + if (sha_out) { + write_hash(sha_out, conv_buf, out_size); + } + break; + case DUMP_BMP: + write_bmp(&fb, rad_name, frameNum); + break; + case DUMP_PNG: + write_png(&fb, rad_name, frameNum); + break; + case DUMP_RAW: + write_raw(&fb, rad_name, frameNum); + break; + + default: + write_texture_file(&fb, rad_name, frameNum, dump_mode_flags); + break; + } + /*unlock it*/ + gf_sc_release_screen_buffer(term->compositor, &fb); +} + +#ifndef GPAC_DISABLE_AVILIB + +typedef struct +{ + GF_AudioListener al; + GF_Mutex *mx; + avi_t *avi; + u32 time_scale; + u64 max_dur, nb_bytes, audio_time; + u32 next_video_time, audio_time_init, flush_retry, nb_write, audio_clock_at_video_init; + u32 samplerate, bits_per_sample, nb_channel; +} AVI_AudioListener; + +void avi_audio_frame(void *udta, char *buffer, u32 buffer_size, u32 time, u32 delay) +{ + AVI_AudioListener *avil = (AVI_AudioListener *)udta; + + if (avil->audio_clock_at_video_init > time) + return; + + if (avil->audio_time >= avil->audio_time_init + avil->max_dur) + return; + + gf_mx_p(avil->mx); + + if (!avil->time_scale) { + AVI_set_audio(avil->avi, avil->nb_channel, avil->samplerate, avil->bits_per_sample, WAVE_FORMAT_PCM, 0); + avil->time_scale = avil->nb_channel*avil->bits_per_sample*avil->samplerate/8; + gf_term_set_option(term, GF_OPT_FORCE_AUDIO_CONFIG, 1); + } + + avil->nb_bytes+=buffer_size; + avil->flush_retry=0; + + if (avil->audio_time >= avil->audio_time_init) { + avil->nb_write++; + AVI_write_audio(avil->avi, buffer, buffer_size); + } + + + avil->audio_time = 1000*avil->nb_bytes/avil->time_scale; + + //we are behind video dump, force audio flush + if (avil->audio_time < avil->next_video_time) { + gf_term_step_clocks(term, 0); + } + gf_mx_v(avil->mx); +} + +void avi_audio_reconfig(void *udta, u32 samplerate, u32 bits_per_sample, u32 nb_channel, u32 channel_cfg) +{ + AVI_AudioListener *avil = (AVI_AudioListener *)udta; + + avil->nb_channel = nb_channel; + avil->samplerate = samplerate; + avil->bits_per_sample = bits_per_sample; +} +#endif + +Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times) +{ + GF_Err e; + u32 i = 0; + GF_VideoSurface fb; + char szPath[GF_MAX_PATH]; + char szOutPath[GF_MAX_PATH]; + char *prev=NULL; + u32 time, prev_time, nb_frames, init_time; + u64 dump_dur; + char *conv_buf = NULL; +#ifndef GPAC_DISABLE_AVILIB + avi_t *avi_out = NULL; + avi_t *depth_avi_out = NULL; + AVI_AudioListener avi_al; + char comp[5]; +#else + void *avi_out = NULL; + void *depth_avi_out = NULL; +#endif + GF_Mutex *avi_mx = NULL; + + FILE *sha_out = NULL; + FILE *sha_depth_out = NULL; + char szPath_depth[GF_MAX_PATH]; + u32 cur_time_idx; + u32 mode = dump_mode_flags & 0x0000FFFF; + + if (!out_url) out_url = url; + prev = strstr(url, "://"); + if (prev) { + prev = strrchr(url, '/'); + if (prev) prev++; + } + + if (!prev) prev = url; + strcpy(szPath, prev); + prev = strrchr(szPath, '.'); + if (prev) prev[0] = 0; + + if (out_url) { + strcpy(szOutPath, out_url); + } else { + strcpy(szOutPath, szPath); + } + prev = strrchr(szOutPath, '.'); + if (prev) prev[0] = 0; + + + fprintf(stderr, "Opening URL %s\n", url); + /*connect in pause mode*/ + gf_term_connect_from_time(term, url, 0, 1); + + while (!term->compositor->scene + || term->compositor->msg_type + || (gf_term_get_option(term, GF_OPT_PLAY_STATE) == GF_STATE_STEP_PAUSE) + ) { + if (last_error) return 1; + gf_term_process_flush(term); + gf_sleep(10); + } + + if (width && height) { + gf_term_set_size(term, width, height); + gf_term_process_flush(term); + } +#ifndef GPAC_USE_TINYGL + e = gf_sc_get_screen_buffer(term->compositor, &fb, 0); +#else + e = gf_sc_get_screen_buffer(term->compositor, &fb, 1); +#endif + if (e != GF_OK) { + fprintf(stderr, "Error grabbing screen buffer: %s\n", gf_error_to_string(e)); + return 0; + } + width = fb.width; + height = fb.height; + gf_sc_release_screen_buffer(term->compositor, &fb); + + if (scale != 1) { + width = (u32)(width * scale); + height = (u32)(height * scale); + gf_term_set_size(term, width, height); + gf_term_process_flush(term); + } + + /*we work in RGB24, and we must make sure the pitch is %4*/ + if ((width*3)%4) { + fprintf(stderr, "Adjusting width (%d) to have a stride multiple of 4\n", width); + while ((width*3)%4) width--; + + gf_term_set_size(term, width, height); + gf_term_process_flush(term); + + gf_sc_get_screen_buffer(term->compositor, &fb, 0); + width = fb.width; + height = fb.height; + gf_sc_release_screen_buffer(term->compositor, &fb); + } + + + strcpy(szPath_depth, szOutPath); + + if (mode==DUMP_AVI) { +#ifdef GPAC_DISABLE_AVILIB + fprintf(stderr, "AVILib is disabled in this build of GPAC\n"); + return 0; +#else + strcat(szOutPath, ".avi"); + avi_out = AVI_open_output_file(szOutPath); + if (!avi_out) { + fprintf(stderr, "Error creating AVI file %s\n", szOutPath); + return 1; + } +#endif + } + + if (mode==DUMP_SHA1) { + strcat(szOutPath, ".sha1"); + sha_out = gf_fopen(szOutPath, "wb"); + if (!sha_out) { + fprintf(stderr, "Error creating SHA file %s\n", szOutPath); + return 1; + } + } + + if (dump_mode_flags & DUMP_DEPTH_ONLY) { + if (mode==DUMP_AVI) { +#ifndef GPAC_DISABLE_AVILIB + strcat(szPath_depth, "_depth.avi"); + depth_avi_out = AVI_open_output_file(szPath_depth); + if (!depth_avi_out) { + fprintf(stderr, "Error creating depth AVI file %s\n", szPath_depth); + return 1; + } +#endif + } + if (mode==DUMP_SHA1) { + strcat(szPath_depth, "_depth.sha1"); + sha_depth_out = gf_fopen(szPath_depth, "wb"); + if (!sha_depth_out) { + fprintf(stderr, "Error creating depgth SHA file %s\n", szPath_depth); + return 1; + } + } + } + + + if (!fps) fps = GF_IMPORT_DEFAULT_FPS; + time = prev_time = 0; + nb_frames = 0; + + if (nb_times==2) { + prev_time = times[0]; + dump_dur = times[1] - times[0]; + } else if ((mode==DUMP_AVI) || (mode==DUMP_SHA1)) { + dump_dur = times[0] ? times[0] : Duration; + } else { + dump_dur = times[nb_times-1]; + dump_dur ++; + } + if (!dump_dur) { + fprintf(stderr, "Warning: file has no duration, defaulting to 1 sec\n"); + dump_dur = 1000; + } + + if (mode==DUMP_AVI) { + avi_mx = gf_mx_new("AVIMutex"); + +#ifndef GPAC_DISABLE_AVILIB + comp[0] = comp[1] = comp[2] = comp[3] = comp[4] = 0; + AVI_set_video(avi_out, width, height, fps, comp); + + if (! (term->user->init_flags & GF_TERM_NO_AUDIO)) { + memset(&avi_al, 0, sizeof(avi_al)); + avi_al.al.udta = &avi_al; + avi_al.al.on_audio_frame = avi_audio_frame; + avi_al.al.on_audio_reconfig = avi_audio_reconfig; + avi_al.mx = avi_mx; + avi_al.avi = avi_out; + avi_al.max_dur=dump_dur; + + gf_sc_add_audio_listener(term->compositor, &avi_al.al); + } + + if (dump_mode_flags & DUMP_DEPTH_ONLY) + AVI_set_video(depth_avi_out, width, height, fps, comp); +#endif + } + + if ((mode==DUMP_AVI) || (mode==DUMP_SHA1)) { + + if (dump_mode_flags & (DUMP_RGB_DEPTH | DUMP_RGB_DEPTH_SHAPE) ) + conv_buf = gf_malloc(sizeof(char) * width * height * 4); + else + conv_buf = gf_malloc(sizeof(char) * width * height * 3); + } + + cur_time_idx = 0; + init_time = 0; + /*step to first frame*/ + if (prev_time) { + gf_term_step_clocks(term, prev_time); + init_time = prev_time; + prev_time=0; + } +#ifndef GPAC_DISABLE_AVILIB + avi_al.audio_time_init = avi_al.next_video_time = init_time; + avi_al.audio_clock_at_video_init = gf_term_get_clock(term); +#endif + + while (time < dump_dur) { + while ((gf_term_get_option(term, GF_OPT_PLAY_STATE) == GF_STATE_STEP_PAUSE)) { + gf_term_process_flush(term); + } + + if ((mode==DUMP_AVI) || (mode==DUMP_SHA1)) { + + if (!no_prog) + fprintf(stderr, "Dumping %02d/100 %% - time %.02f sec\r", (u32) ((100.0*prev_time)/dump_dur), prev_time/1000.0 ); + + if (avi_mx) gf_mx_p(avi_mx); + + if (dump_mode_flags & DUMP_DEPTH_ONLY) { + + /*we'll dump both buffers at once*/ + gf_mx_p(term->compositor->mx); + dump_depth(term, szPath_depth, dump_mode_flags, i+1, conv_buf, depth_avi_out, sha_depth_out); + dump_frame(term, szOutPath, mode, i+1, conv_buf, avi_out, sha_out); + gf_mx_v(term->compositor->mx); + } else { + dump_frame(term, szOutPath, dump_mode_flags, i+1, conv_buf, avi_out, sha_out); + } + + if (avi_mx) gf_mx_v(avi_mx); + + } else { + if ( times[cur_time_idx] <= time) { + if (dump_mode_flags & (DUMP_DEPTH_ONLY | DUMP_RGB_DEPTH | DUMP_RGB_DEPTH_SHAPE) ) { + dump_depth(term, szOutPath, dump_mode_flags, cur_time_idx+1, NULL, NULL, NULL); + } else { + dump_frame(term, out_url, dump_mode_flags, cur_time_idx+1, NULL, NULL, NULL); + } + + cur_time_idx++; + if (cur_time_idx>=nb_times) + break; + } + } + + nb_frames++; + time = (u32) (nb_frames*1000/fps); +#ifndef GPAC_DISABLE_AVILIB + avi_al.next_video_time = init_time + time; +#endif + gf_term_step_clocks(term, time - prev_time); + prev_time = time; + + if (gf_prompt_has_input() && (gf_prompt_get_char()=='q')) { + fprintf(stderr, "Aborting dump\n"); + dump_dur=0; + break; + } + } + +#ifndef GPAC_DISABLE_AVILIB + //flush audio dump + if (! (term->user->init_flags & GF_TERM_NO_AUDIO)) { + avi_al.flush_retry=0; + while ((avi_al.flush_retry <100) && (avi_al.audio_time < dump_dur)) { + gf_term_step_clocks(term, 0); + gf_sleep(1); + avi_al.flush_retry++; + } + } + + if (! (term->user->init_flags & GF_TERM_NO_AUDIO)) { + gf_sc_remove_audio_listener(term->compositor, &avi_al.al); + } + if (avi_out) AVI_close(avi_out); + if (depth_avi_out) AVI_close(depth_avi_out); + if (avi_mx) gf_mx_del(avi_mx); +#endif + + if (sha_out) gf_fclose(sha_out); + if (sha_depth_out) gf_fclose(sha_depth_out); + + if (conv_buf) { + gf_free(conv_buf); + fprintf(stderr, "Dumping done: %d frames at %g FPS\n", nb_frames, fps); + } + + return 0; +} + diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c new file mode 100644 index 0000000..074ba52 --- /dev/null +++ b/applications/mp4client/main.c @@ -0,0 +1,2934 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2005-2012 + * All rights reserved + * + * This file is part of GPAC / command-line client + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/*includes both terminal and od browser*/ +#include +#include +#include +#include +#include +#include +#include +#include + +/*ISO 639 languages*/ +#include + +//FIXME we need a plugin for playlists +#include + + +#ifndef WIN32 +#include +#include +#include +#if defined(__DARWIN__) || defined(__APPLE__) +#include +#include + +void carbon_init(); +void carbon_uninit(); + +#endif + +#else +#include /*for GetModuleFileName*/ +#endif //WIN32 + +/*local prototypes*/ +void PrintWorldInfo(GF_Terminal *term); +void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number, const char *URL); +void PrintODList(GF_Terminal *term, GF_ObjectManager *root_odm, u32 num, u32 indent, char *root_name); + +void ViewODs(GF_Terminal *term, Bool show_timing); +void PrintGPACConfig(); + +static u32 gui_mode = 0; + +static Bool restart = GF_FALSE; +static Bool reload = GF_FALSE; + +Bool no_prog = 0; + +#if defined(__DARWIN__) || defined(__APPLE__) +//we keep no decoder thread because of JS_GC deadlocks between threads ... +static u32 threading_flags = GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_DECODER_THREAD; +#define VK_MOD GF_KEY_MOD_ALT +#else +static u32 threading_flags = 0; +#define VK_MOD GF_KEY_MOD_CTRL +#endif +static Bool no_audio = GF_FALSE; +static Bool term_step = GF_FALSE; +static Bool no_regulation = GF_FALSE; +static u32 bench_mode = 0; +static u32 bench_mode_start = 0; +static u32 bench_buffer = 0; +static Bool eos_seen = GF_FALSE; +static Bool addon_visible = GF_TRUE; +Bool is_connected = GF_FALSE; +Bool startup_file = GF_FALSE; +GF_User user; +GF_Terminal *term; +u64 Duration; +GF_Err last_error = GF_OK; +static Bool enable_add_ons = GF_TRUE; +static Fixed playback_speed = FIX_ONE; + +static s32 request_next_playlist_item = GF_FALSE; +FILE *playlist = NULL; +static Bool readonly_playlist = GF_FALSE; + +static GF_Config *cfg_file; +static u32 display_rti = 0; +static Bool Run; +static Bool CanSeek = GF_FALSE; +static char the_url[GF_MAX_PATH]; +static char pl_path[GF_MAX_PATH]; +static Bool no_mime_check = GF_TRUE; +static Bool be_quiet = GF_FALSE; +static u64 log_time_start = 0; +static Bool log_utc_time = GF_FALSE; +static Bool loop_at_end = GF_FALSE; +static u32 forced_width=0; +static u32 forced_height=0; + +/*windowless options*/ +u32 align_mode = 0; +u32 init_w = 0; +u32 init_h = 0; +u32 last_x, last_y; +Bool right_down = GF_FALSE; + +void dump_frame(GF_Terminal *term, char *rad_path, u32 dump_type, u32 frameNum); + +enum +{ + DUMP_NONE = 0, + DUMP_AVI = 1, + DUMP_BMP = 2, + DUMP_PNG = 3, + DUMP_RAW = 4, + DUMP_SHA1 = 5, + + //DuMP flags + DUMP_DEPTH_ONLY = 1<<16, + DUMP_RGB_DEPTH = 1<<17, + DUMP_RGB_DEPTH_SHAPE = 1<<18 +}; + +Bool dump_file(char *the_url, char *out_url, u32 dump_mode, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times); + + +static Bool shell_visible = GF_TRUE; +void hide_shell(u32 cmd_type) +{ +#if defined(WIN32) && !defined(_WIN32_WCE) + typedef HWND (WINAPI *GetConsoleWindowT)(void); + HMODULE hk32 = GetModuleHandle("kernel32.dll"); + GetConsoleWindowT GetConsoleWindow = (GetConsoleWindowT ) GetProcAddress(hk32,"GetConsoleWindow"); + if (cmd_type==0) { + ShowWindow( GetConsoleWindow(), SW_SHOW); + shell_visible = GF_TRUE; + } + else if (cmd_type==1) { + ShowWindow( GetConsoleWindow(), SW_HIDE); + shell_visible = GF_FALSE; + } + else if (cmd_type==2) PostMessage(GetConsoleWindow(), WM_CLOSE, 0, 0); + +#endif +} + + +void send_open_url(const char *url) +{ + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_NAVIGATE; + evt.navigate.to_url = url; + gf_term_send_event(term, &evt); +} + +void PrintUsage() +{ + fprintf(stderr, "Usage MP4Client [options] [filename]\n" + "\t-c fileName: user-defined configuration file. Also works with -cfg\n" +#ifdef GPAC_MEMORY_TRACKING + "\t-mem-track: enables memory tracker\n" +#endif + "\t-rti fileName: logs run-time info (FPS, CPU, Mem usage) to file\n" + "\t-rtix fileName: same as -rti but driven by GPAC logs\n" + "\t-quiet: removes script message, buffering and downloading status\n" + "\t-strict-error: exit when the player reports its first error\n" + "\t-opt option: Overrides an option in the configuration file. String format is section:key=value. \n" + "\t \"section:key=null\" removes the key\n" + "\t \"section:*=null\" removes the section\n" + "\t-conf option: Same as -opt but does not start player.\n" + "\t-log-file file: sets output log file. Also works with -lf\n" + "\t-logs log_args: sets log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" + "\t levelX can be one of:\n" + "\t \"quiet\" : skip logs\n" + "\t \"error\" : logs only error messages\n" + "\t \"warning\" : logs error+warning messages\n" + "\t \"info\" : logs error+warning+info messages\n" + "\t \"debug\" : logs all messages\n" + "\t toolX can be one of:\n" + "\t \"core\" : libgpac core\n" + "\t \"coding\" : bitstream formats (audio, video, scene)\n" + "\t \"container\" : container formats (ISO File, MPEG-2 TS, AVI, ...)\n" + "\t \"network\" : network data exept RTP trafic\n" + "\t \"rtp\" : rtp trafic\n" + "\t \"author\" : authoring tools (hint, import, export)\n" + "\t \"sync\" : terminal sync layer\n" + "\t \"codec\" : terminal codec messages\n" + "\t \"parser\" : scene parsers (svg, xmt, bt) and other\n" + "\t \"media\" : terminal media object management\n" + "\t \"scene\" : scene graph and scene manager\n" + "\t \"script\" : scripting engine messages\n" + "\t \"interact\" : interaction engine (events, scripts, etc)\n" + "\t \"smil\" : SMIL timing engine\n" + "\t \"compose\" : composition engine (2D, 3D, etc)\n" + "\t \"mmio\" : Audio/Video HW I/O management\n" + "\t \"rti\" : various run-time stats\n" + "\t \"cache\" : HTTP cache subsystem\n" + "\t \"audio\" : Audio renderer and mixers\n" +#ifdef GPAC_MEMORY_TRACKING + "\t \"mem\" : GPAC memory tracker\n" +#endif +#ifndef GPAC_DISABLE_DASH_CLIENT + "\t \"dash\" : HTTP streaming logs\n" +#endif + "\t \"module\" : GPAC modules debugging\n" + "\t \"mutex\" : mutex\n" + "\t \"all\" : all tools logged - other tools can be specified afterwards.\n" + "\n" + "\t-log-clock or -lc : logs time in micro sec since start time of GPAC before each log line.\n" + "\t-log-utc or -lu : logs UTC time in ms before each log line.\n" + "\t-ifce IPIFCE : Sets default Multicast interface\n" + "\t-size WxH: specifies visual size (default: scene size)\n" +#if defined(__DARWIN__) || defined(__APPLE__) + "\t-thread: enables thread usage for terminal and compositor \n" +#else + "\t-no-thread: disables thread usage (except for audio)\n" +#endif + "\t-no-compositor-thread: disables compositor thread (iOS and Android mode)\n" + "\t-no-audio: disables audio \n" + "\t-no-wnd: uses windowless mode (Win32 only)\n" + "\t-no-back: uses transparent background for output window when no background is specified (Win32 only)\n" + "\t-align vh: specifies v and h alignment for windowless mode\n" + "\t possible v values: t(op), m(iddle), b(ottom)\n" + "\t possible h values: l(eft), m(iddle), r(ight)\n" + "\t default alignment is top-left\n" + "\t default alignment is top-left\n" + "\t-pause: pauses at first frame\n" + "\t-play-from T: starts from T seconds in media\n" + "\t-speed S: starts with speed S\n" + "\t-loop: loops presentation\n" + "\t-no-regulation: disables framerate regulation\n" + "\t-bench: disable a/v output and bench source decoding (as fast as possible)\n" + "\t-vbench: disable audio output, video sync bench source decoding/display (as fast as possible)\n" + "\t-sbench: disable all decoders and bench systems layer (as fast as possible)\n" + "\t-fs: starts in fullscreen mode\n" + "\t-views v1:.:vN: creates an auto-stereo scene of N views. vN can be any type of URL supported by GPAC.\n" + "\t in this mode, URL argument of GPAC is ignored, GUI as well.\n" + "\t this is equivalent as using views://v1:.:N as an URL.\n" + "\n" + "\t-exit: automatically exits when presentation is over\n" + "\t-run-for TIME: runs for TIME seconds and exits\n" + "\t-service ID: auto-tune to given service ID in a multiplex\n" + "\t-noprog: disable progress report\n" + "\t-no-save: disable saving config file on exit\n" + "\t-no-addon: disable automatic loading of media addons declared in source URL\n" + "\t-gui: starts in GUI mode. The GUI is indicated in GPAC config, section General, by the key [StartupFile]\n" + "\n" + "Dumper Options (times is a formated as start-end, with start being sec, h:m:s:f/fps or h:m:s:ms):\n" + "\t-bmp [times]: dumps given frames to bmp\n" + "\t-png [times]: dumps given frames to png\n" + "\t-raw [times]: dumps given frames to raw\n" + "\t-avi [times]: dumps given file to raw avi\n" + "\t-sha [times]: dumps given file to raw SHA-1 (1 hash per frame)\n" + "\r-out filename: name of the output file\n" + "\t-rgbds: dumps the RGBDS pixel format texture\n" + "\t with -avi [times]: dumps an rgbds-format .avi\n" + "\t-rgbd: dumps the RGBD pixel format texture\n" + "\t with -avi [times]: dumps an rgbd-format .avi\n" + "\t-depth: dumps depthmap (z-buffer) frames\n" + "\t with -avi [times]: dumps depthmap in grayscale .avi\n" + "\t with -bmp: dumps depthmap in grayscale .bmp\n" + "\t with -png: dumps depthmap in grayscale .png\n" + "\t-fps FPS: specifies frame rate for AVI dumping (default: %f)\n" + "\t-scale s: scales the visual size (default: 1)\n" + "\t-fill: uses fill aspect ratio for dumping (default: none)\n" + "\t-show: shows window while dumping (default: no)\n" + "\n" + "\t-help: shows this screen\n" + "\n" + "MP4Client - GPAC command line player and dumper - version "GPAC_FULL_VERSION"\n" + "GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n" + "GPAC Configuration: " GPAC_CONFIGURATION "\n" + "Features: %s\n", + GF_IMPORT_DEFAULT_FPS, + gpac_features() + ); +} + +void PrintHelp() +{ + fprintf(stderr, "MP4Client command keys:\n" + "\tq: quit\n" + "\tX: kill\n" + "\to: connect to the specified URL\n" + "\tO: connect to the specified playlist\n" + "\tN: switch to the next URL in the playlist. Also works with \\n\n" + "\tP: jumps to a given number ahead in the playlist\n" + "\tr: reload current presentation\n" + "\tD: disconnects the current presentation\n" + "\tG: selects object or service ID\n" + "\n" + "\tp: play/pause the presentation\n" + "\ts: step one frame ahead\n" + "\tz: seek into presentation by percentage\n" + "\tT: seek into presentation by time\n" + "\tt: print current timing\n" + "\n" + "\tu: sends a command (BIFS or LASeR) to the main scene\n" + "\te: evaluates JavaScript code\n" + "\tZ: dumps output video to PNG\n" + "\n" + "\tw: view world info\n" + "\tv: view Object Descriptor list\n" + "\ti: view Object Descriptor info (by ID)\n" + "\tj: view Object Descriptor info (by number)\n" + "\tb: view media objects timing and buffering info\n" + "\tm: view media objects buffering and memory info\n" + "\td: dumps scene graph\n" + "\n" + "\tk: turns stress mode on/off\n" + "\tn: changes navigation mode\n" + "\tx: reset to last active viewpoint\n" + "\n" + "\t3: switch OpenGL on or off for 2D scenes\n" + "\n" + "\t4: forces 4/3 Aspect Ratio\n" + "\t5: forces 16/9 Aspect Ratio\n" + "\t6: forces no Aspect Ratio (always fill screen)\n" + "\t7: forces original Aspect Ratio (default)\n" + "\n" + "\tL: changes to new log level. CF MP4Client usage for possible values\n" + "\tT: select new tools to log. CF MP4Client usage for possible values\n" + "\n" + "\tl: list available modules\n" + "\tc: prints some GPAC configuration info\n" + "\tE: forces reload of GPAC configuration\n" + "\n" + "\tR: toggles run-time info display in window title bar on/off\n" + "\tF: toggle displaying of FPS in stderr on/off\n" + "\tg: print GPAC allocated memory\n" + "\th: print this message\n" + "\n" + "\tEXPERIMENTAL/UNSTABLE OPTIONS\n" + "\tC: Enable Streaming Cache\n" + "\tS: Stops Streaming Cache and save to file\n" + "\tA: Aborts Streaming Cache\n" + "\tM: specifies video cache memory for 2D objects\n" + "\n" + "MP4Client - GPAC command line player - version %s\n" + "GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n", + + GPAC_FULL_VERSION + ); +} + + +static void PrintTime(u64 time) +{ + u32 ms, h, m, s; + h = (u32) (time / 1000 / 3600); + m = (u32) (time / 1000 / 60 - h*60); + s = (u32) (time / 1000 - h*3600 - m*60); + ms = (u32) (time - (h*3600 + m*60 + s) * 1000); + fprintf(stderr, "%02d:%02d:%02d.%03d", h, m, s, ms); +} + +void PrintAVInfo(Bool final); + + +static u32 rti_update_time_ms = 200; +static FILE *rti_logs = NULL; + +static void UpdateRTInfo(const char *legend) +{ + GF_SystemRTInfo rti; + + /*refresh every second*/ + if (!display_rti && !rti_logs) return; + if (!gf_sys_get_rti(rti_update_time_ms, &rti, 0) && !legend) + return; + + if (display_rti) { + char szMsg[1024]; + + if (rti.total_cpu_usage && (bench_mode<2) ) { + sprintf(szMsg, "FPS %02.02f CPU %2d (%02d) Mem %d kB", + gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024)); + } else { + sprintf(szMsg, "FPS %02.02f CPU %02d Mem %d kB", + gf_term_get_framerate(term, 0), rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) ); + } + + if (display_rti==2) { + if (bench_mode>=2) { + PrintAVInfo(GF_FALSE); + } + fprintf(stderr, "%s\r", szMsg); + } else { + GF_Event evt; + evt.type = GF_EVENT_SET_CAPTION; + evt.caption.caption = szMsg; + gf_term_user_event(term, &evt); + } + } + if (rti_logs) { + fprintf(rti_logs, "% 8d\t% 8d\t% 8d\t% 4d\t% 8d\t%s", + gf_sys_clock(), + gf_term_get_time_in_ms(term), + rti.total_cpu_usage, + (u32) gf_term_get_framerate(term, 0), + (u32) (rti.gpac_memory / 1024), + legend ? legend : "" + ); + if (!legend) fprintf(rti_logs, "\n"); + } +} + +static void ResetCaption() +{ + GF_Event event; + if (display_rti) return; + event.type = GF_EVENT_SET_CAPTION; + if (is_connected) { + char szName[1024]; + NetInfoCommand com; + + event.caption.caption = NULL; + /*get any service info*/ + if (!startup_file && gf_term_get_service_info(term, gf_term_get_root_object(term), &com) == GF_OK) { + strcpy(szName, ""); + if (com.track_info) { + char szBuf[10]; + sprintf(szBuf, "%02d ", (u32) (com.track_info>>16) ); + strcat(szName, szBuf); + } + if (com.artist) { + strcat(szName, com.artist); + strcat(szName, " "); + } + if (com.name) { + strcat(szName, com.name); + strcat(szName, " "); + } + if (com.album) { + strcat(szName, "("); + strcat(szName, com.album); + strcat(szName, ")"); + } + if (com.provider) { + strcat(szName, "("); + strcat(szName, com.provider); + strcat(szName, ")"); + } + + if (strlen(szName)) event.caption.caption = szName; + } + if (!event.caption.caption) { + char *str = strrchr(the_url, '\\'); + if (!str) str = strrchr(the_url, '/'); + event.caption.caption = str ? str+1 : the_url; + } + } else { + event.caption.caption = "GPAC MP4Client " GPAC_FULL_VERSION; + } + gf_term_user_event(term, &event); +} + +#ifdef WIN32 +u32 get_sys_col(int idx) +{ + u32 res; + DWORD val = GetSysColor(idx); + res = (val)&0xFF; + res<<=8; + res |= (val>>8)&0xFF; + res<<=8; + res |= (val>>16)&0xFF; + return res; +} +#endif + +void switch_bench(u32 is_on) +{ + bench_mode = is_on; + display_rti = is_on ? 2 : 0; + ResetCaption(); + gf_term_set_option(term, GF_OPT_VIDEO_BENCH, is_on); +} + +#ifndef WIN32 +#include +int getch() { + struct termios old; + struct termios new; + int rc; + if (tcgetattr(0, &old) == -1) { + return -1; + } + new = old; + new.c_lflag &= ~(ICANON | ECHO); + new.c_cc[VMIN] = 1; + new.c_cc[VTIME] = 0; + if (tcsetattr(0, TCSANOW, &new) == -1) { + return -1; + } + rc = getchar(); + (void) tcsetattr(0, TCSANOW, &old); + return rc; +} +#else +int getch() { + return getchar(); +} +#endif + +/** + * Reads a line of input from stdin + * @param line the buffer to fill + * @param maxSize the maximum size of the line to read + * @param showContent boolean indicating if the line read should be printed on stderr or not + */ +static const char * read_line_input(char * line, int maxSize, Bool showContent) { + char read; + int i = 0; + if (fflush( stderr )) + perror("Failed to flush buffer %s"); + do { + line[i] = '\0'; + if (i >= maxSize - 1) + return line; + read = getch(); + if (read == 8 || read == 127) { + if (i > 0) { + fprintf(stderr, "\b \b"); + i--; + } + } else if (read > 32) { + fputc(showContent ? read : '*', stderr); + line[i++] = read; + } + fflush(stderr); + } while (read != '\n'); + if (!read) + return 0; + return line; +} + +static void do_set_speed(Fixed desired_speed) +{ + if (gf_term_set_speed(term, desired_speed) == GF_OK) { + playback_speed = desired_speed; + fprintf(stderr, "Playing at %g speed\n", FIX2FLT(playback_speed)); + } else { + fprintf(stderr, "Adjusting speed to %g not supported for this content\n", FIX2FLT(desired_speed)); + } +} + +Bool GPAC_EventProc(void *ptr, GF_Event *evt) +{ + if (!term) return 0; + + if (gui_mode==1) { + if (evt->type==GF_EVENT_QUIT) { + Run = 0; + } else if (evt->type==GF_EVENT_KEYDOWN) { + switch (evt->key.key_code) { + case GF_KEY_C: + if (evt->key.flags & (GF_KEY_MOD_CTRL|GF_KEY_MOD_ALT)) { + hide_shell(shell_visible ? 1 : 0); + if (shell_visible) gui_mode=2; + } + break; + default: + break; + } + } + return 0; + } + + switch (evt->type) { + case GF_EVENT_DURATION: + Duration = (u64) ( 1000 * (s64) evt->duration.duration); + CanSeek = evt->duration.can_seek; + break; + case GF_EVENT_MESSAGE: + { + const char *servName; + if (!evt->message.service || !strcmp(evt->message.service, the_url)) { + servName = ""; + } else if (!strnicmp(evt->message.service, "data:", 5)) { + servName = "(embedded data)"; + } else { + servName = evt->message.service; + } + + + if (!evt->message.message) return 0; + + if (evt->message.error) { + if (!is_connected) last_error = evt->message.error; + if (evt->message.error==GF_SCRIPT_INFO) { + GF_LOG(GF_LOG_INFO, GF_LOG_CONSOLE, ("%s\n", evt->message.message)); + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONSOLE, ("%s %s: %s\n", servName, evt->message.message, gf_error_to_string(evt->message.error))); + } + } else if (!be_quiet) + GF_LOG(GF_LOG_INFO, GF_LOG_CONSOLE, ("%s %s\n", servName, evt->message.message)); + } + break; + case GF_EVENT_PROGRESS: + { + char *szTitle = ""; + if (evt->progress.progress_type==0) { + szTitle = "Buffer "; + if (bench_mode && (bench_mode!=3) ) { + if (evt->progress.done >= evt->progress.total) bench_buffer = 0; + else bench_buffer = 1 + 100*evt->progress.done / evt->progress.total; + break; + } + } + else if (evt->progress.progress_type==1) { + if (bench_mode) break; + szTitle = "Download "; + } + else if (evt->progress.progress_type==2) szTitle = "Import "; + gf_set_progress(szTitle, evt->progress.done, evt->progress.total); + } + break; + + + case GF_EVENT_DBLCLICK: + gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN)); + return 0; + + case GF_EVENT_MOUSEDOWN: + if (evt->mouse.button==GF_MOUSE_RIGHT) { + right_down = 1; + last_x = evt->mouse.x; + last_y = evt->mouse.y; + } + return 0; + case GF_EVENT_MOUSEUP: + if (evt->mouse.button==GF_MOUSE_RIGHT) { + right_down = 0; + last_x = evt->mouse.x; + last_y = evt->mouse.y; + } + return 0; + case GF_EVENT_MOUSEMOVE: + if (right_down && (user.init_flags & GF_TERM_WINDOWLESS) ) { + GF_Event move; + move.move.x = evt->mouse.x - last_x; + move.move.y = last_y-evt->mouse.y; + move.type = GF_EVENT_MOVE; + move.move.relative = 1; + gf_term_user_event(term, &move); + } + return 0; + + case GF_EVENT_KEYUP: + switch (evt->key.key_code) { + case GF_KEY_SPACE: + if (evt->key.flags & GF_KEY_MOD_CTRL) switch_bench(!bench_mode); + break; + } + break; + case GF_EVENT_KEYDOWN: + gf_term_process_shortcut(term, evt); + switch (evt->key.key_code) { + case GF_KEY_SPACE: + if (evt->key.flags & GF_KEY_MOD_CTRL) { + /*ignore key repeat*/ + if (!bench_mode) switch_bench(!bench_mode); + } + break; + case GF_KEY_PAGEDOWN: + case GF_KEY_MEDIANEXTTRACK: + request_next_playlist_item = 1; + break; + case GF_KEY_MEDIAPREVIOUSTRACK: + break; + case GF_KEY_ESCAPE: + gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN)); + break; + case GF_KEY_C: + if (evt->key.flags & (GF_KEY_MOD_CTRL|GF_KEY_MOD_ALT)) { + hide_shell(shell_visible ? 1 : 0); + if (!shell_visible) gui_mode=1; + } + break; + case GF_KEY_F: + if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Rendering rate: %f FPS\n", gf_term_get_framerate(term, 0)); + break; + case GF_KEY_T: + if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Scene Time: %f \n", gf_term_get_time_in_ms(term)/1000.0); + break; + case GF_KEY_D: + if (evt->key.flags & GF_KEY_MOD_CTRL) gf_term_set_option(term, GF_OPT_DRAW_MODE, (gf_term_get_option(term, GF_OPT_DRAW_MODE)==GF_DRAW_MODE_DEFER) ? GF_DRAW_MODE_IMMEDIATE : GF_DRAW_MODE_DEFER ); + break; + case GF_KEY_4: + if (evt->key.flags & GF_KEY_MOD_CTRL) + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3); + break; + case GF_KEY_5: + if (evt->key.flags & GF_KEY_MOD_CTRL) + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9); + break; + case GF_KEY_6: + if (evt->key.flags & GF_KEY_MOD_CTRL) + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN); + break; + case GF_KEY_7: + if (evt->key.flags & GF_KEY_MOD_CTRL) + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP); + break; + case GF_KEY_O: + if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { + if (gf_term_get_option(term, GF_OPT_MAIN_ADDON)) { + fprintf(stderr, "Resuming to main content\n"); + gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_PLAY_LIVE); + } else { + fprintf(stderr, "Main addon not enabled\n"); + } + } + break; + case GF_KEY_P: + if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { + u32 is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE) ; + fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused"); + if ((is_pause == GF_STATE_PAUSED) && (evt->key.flags & GF_KEY_MOD_SHIFT)) { + gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_PLAY_LIVE); + } else { + gf_term_set_option(term, GF_OPT_PLAY_STATE, (gf_term_get_option(term, GF_OPT_PLAY_STATE)==GF_STATE_PAUSED) ? GF_STATE_PLAYING : GF_STATE_PAUSED); + } + } + break; + case GF_KEY_S: + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) { + gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE); + fprintf(stderr, "Step time: "); + PrintTime(gf_term_get_time_in_ms(term)); + fprintf(stderr, "\n"); + } + break; + case GF_KEY_B: + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) + ViewODs(term, 1); + break; + case GF_KEY_M: + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) + ViewODs(term, 0); + break; + case GF_KEY_H: + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) + gf_term_switch_quality(term, 1); + break; + case GF_KEY_L: + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) + gf_term_switch_quality(term, 0); + break; + case GF_KEY_F5: + if (is_connected) + reload = 1; + break; + case GF_KEY_A: + addon_visible = !addon_visible; + gf_term_toggle_addons(term, addon_visible); + break; + case GF_KEY_UP: + if (evt->key.flags & VK_MOD && is_connected) { + do_set_speed(playback_speed * 2); + } + break; + case GF_KEY_DOWN: + if (evt->key.flags & VK_MOD && is_connected) { + do_set_speed(playback_speed / 2); + } + break; + case GF_KEY_LEFT: + if (evt->key.flags & VK_MOD && is_connected) { + do_set_speed(-1 * playback_speed ); + } + break; + + } + break; + + case GF_EVENT_CONNECT: + if (evt->connect.is_connected) { + is_connected = 1; + fprintf(stderr, "Service Connected\n"); + eos_seen = GF_FALSE; + if (playback_speed != FIX_ONE) + gf_term_set_speed(term, playback_speed); + + } else if (is_connected) { + fprintf(stderr, "Service %s\n", is_connected ? "Disconnected" : "Connection Failed"); + is_connected = 0; + Duration = 0; + } + if (init_w && init_h) { + gf_term_set_size(term, init_w, init_h); + } + ResetCaption(); + break; + case GF_EVENT_EOS: + eos_seen = GF_TRUE; + if (!playlist && loop_at_end) restart = 1; + break; + case GF_EVENT_SIZE: + if (user.init_flags & GF_TERM_WINDOWLESS) { + GF_Event move; + move.type = GF_EVENT_MOVE; + move.move.align_x = align_mode & 0xFF; + move.move.align_y = (align_mode>>8) & 0xFF; + move.move.relative = 2; + gf_term_user_event(term, &move); + } + break; + case GF_EVENT_SCENE_SIZE: + if (forced_width && forced_height) { + GF_Event size; + size.type = GF_EVENT_SIZE; + size.size.width = forced_width; + size.size.height = forced_height; + gf_term_user_event(term, &size); + } + break; + + case GF_EVENT_METADATA: + ResetCaption(); + break; + + case GF_EVENT_DROPFILE: + { + u32 i, pos; + /*todo - force playlist mode*/ + if (readonly_playlist) { + gf_fclose(playlist); + playlist = NULL; + } + readonly_playlist = 0; + if (!playlist) { + readonly_playlist = 0; + playlist = gf_temp_file_new(); + } + pos = ftell(playlist); + i=0; + while (iopen_file.nb_files) { + if (evt->open_file.files[i] != NULL) { + fprintf(playlist, "%s\n", evt->open_file.files[i]); + } + i++; + } + fseek(playlist, pos, SEEK_SET); + request_next_playlist_item = 1; + } + return 1; + + case GF_EVENT_QUIT: + if (evt->message.error) { + fprintf(stderr, "A fatal error was encoutered: %s (%s) - exiting ...\n", evt->message.message ? evt->message.message : "no details", gf_error_to_string(evt->message.error) ); + } + Run = 0; + break; + case GF_EVENT_DISCONNECT: + gf_term_disconnect(term); + break; + case GF_EVENT_MIGRATE: + { + } + break; + case GF_EVENT_NAVIGATE_INFO: + if (evt->navigate.to_url) fprintf(stderr, "Go to URL: \"%s\"\r", evt->navigate.to_url); + break; + case GF_EVENT_NAVIGATE: + if (gf_term_is_supported_url(term, evt->navigate.to_url, 1, no_mime_check)) { + strcpy(the_url, evt->navigate.to_url); + fprintf(stderr, "Navigating to URL %s\n", the_url); + gf_term_navigate_to(term, evt->navigate.to_url); + return 1; + } else { + fprintf(stderr, "Navigation destination not supported\nGo to URL: %s\n", evt->navigate.to_url); + } + break; + case GF_EVENT_SET_CAPTION: + gf_term_user_event(term, evt); + break; + case GF_EVENT_AUTHORIZATION: + { + int maxTries = 1; + assert( evt->type == GF_EVENT_AUTHORIZATION); + assert( evt->auth.user); + assert( evt->auth.password); + assert( evt->auth.site_url); + while ((!strlen(evt->auth.user) || !strlen(evt->auth.password)) && (maxTries--) >= 0) { + fprintf(stderr, "**** Authorization required for site %s ****\n", evt->auth.site_url); + fprintf(stderr, "login : "); + read_line_input(evt->auth.user, 50, 1); + fprintf(stderr, "\npassword: "); + read_line_input(evt->auth.password, 50, 0); + fprintf(stderr, "*********\n"); + } + if (maxTries < 0) { + fprintf(stderr, "**** No User or password has been filled, aborting ***\n"); + return 0; + } + return 1; + } + case GF_EVENT_ADDON_DETECTED: + if (enable_add_ons) { + fprintf(stderr, "Media Addon %s detected - enabling it\n", evt->addon_connect.addon_url); + addon_visible = 1; + } + return enable_add_ons; + } + return 0; +} + + +void list_modules(GF_ModuleManager *modules) +{ + u32 i; + fprintf(stderr, "\rAvailable modules:\n"); + for (i=0; i +#endif + +static void progress_quiet(const void *cbck, const char *title, u64 done, u64 total) { } + +int main (int argc, char **argv) +{ + char c; + const char *str; + u32 i, times[100], nb_times, dump_mode; + u32 simulation_time_in_ms = 0; + u32 initial_service_id = 0; + Bool auto_exit = GF_FALSE; + Bool logs_set = GF_FALSE; + Bool start_fs = GF_FALSE; + Bool use_rtix = GF_FALSE; + Bool pause_at_first = GF_FALSE; + Bool no_cfg_save = GF_FALSE; + Bool is_cfg_only = GF_FALSE; + + Double play_from = 0; +#ifdef GPAC_MEMORY_TRACKING + Bool enable_mem_tracker = GF_FALSE; +#endif + Double fps = GF_IMPORT_DEFAULT_FPS; + Bool fill_ar, visible; + char *url_arg, *out_arg, *the_cfg, *rti_file, *views, *default_com; + FILE *logfile = NULL; + Float scale = 1; +#ifndef WIN32 + dlopen(NULL, RTLD_NOW|RTLD_GLOBAL); +#endif + + /*by default use current dir*/ + strcpy(the_url, "."); + + memset(&user, 0, sizeof(GF_User)); + + dump_mode = DUMP_NONE; + fill_ar = visible = GF_FALSE; + url_arg = out_arg = the_cfg = rti_file = views = default_com = NULL; + nb_times = 0; + times[0] = 0; + + /*first locate config file if specified*/ + for (i=1; i<(u32) argc; i++) { + char *arg = argv[i]; + if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) { + the_cfg = argv[i+1]; + i++; + } + else if (!strcmp(arg, "-mem-track")) { +#ifdef GPAC_MEMORY_TRACKING + enable_mem_tracker = GF_TRUE; +#else + fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n"); +#endif + } else if (!strcmp(arg, "-gui")) { + gui_mode = 1; + } else if (!strcmp(arg, "-guid")) { + gui_mode = 2; + } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) { + PrintUsage(); + return 1; + } + } + +#ifdef GPAC_MEMORY_TRACKING + gf_sys_init(enable_mem_tracker); +#else + gf_sys_init(GF_FALSE); +#endif + gf_sys_set_args(argc, (const char **) argv); + + cfg_file = gf_cfg_init(the_cfg, NULL); + if (!cfg_file) { + fprintf(stderr, "Error: Configuration File not found\n"); + return 1; + } + /*if logs are specified, use them*/ + if (gf_log_set_tools_levels( gf_cfg_get_key(cfg_file, "General", "Logs") ) != GF_OK) { + return 1; + } + + if( gf_cfg_get_key(cfg_file, "General", "Logs") != NULL ) { + logs_set = GF_TRUE; + } + + if (!gui_mode) { + str = gf_cfg_get_key(cfg_file, "General", "ForceGUI"); + if (str && !strcmp(str, "yes")) gui_mode = 1; + } + + for (i=1; i<(u32) argc; i++) { + char *arg = argv[i]; + + if (!strcmp(arg, "-rti")) { + rti_file = argv[i+1]; + i++; + } else if (!strcmp(arg, "-rtix")) { + rti_file = argv[i+1]; + i++; + use_rtix = GF_TRUE; + } else if (!stricmp(arg, "-size")) { + /*usage of %ud breaks sscanf on MSVC*/ + if (sscanf(argv[i+1], "%dx%d", &forced_width, &forced_height) != 2) { + forced_width = forced_height = 0; + } + i++; + } else if (!strcmp(arg, "-quiet")) { + be_quiet = 1; + } else if (!strcmp(arg, "-strict-error")) { + gf_log_set_strict_error(1); + } else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) { + logfile = gf_fopen(argv[i+1], "wt"); + gf_log_set_callback(logfile, on_gpac_log); + i++; + } else if (!strcmp(arg, "-logs") ) { + if (gf_log_set_tools_levels(argv[i+1]) != GF_OK) { + return 1; + } + logs_set = GF_TRUE; + i++; + } else if (!strcmp(arg, "-log-clock") || !strcmp(arg, "-lc")) { + log_time_start = 1; + } else if (!strcmp(arg, "-log-utc") || !strcmp(arg, "-lu")) { + log_utc_time = 1; + } +#if defined(__DARWIN__) || defined(__APPLE__) + else if (!strcmp(arg, "-thread")) threading_flags = 0; +#else + else if (!strcmp(arg, "-no-thread")) threading_flags = GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_WINDOW_NO_THREAD; +#endif + else if (!strcmp(arg, "-no-compositor-thread")) threading_flags |= GF_TERM_NO_COMPOSITOR_THREAD; + else if (!strcmp(arg, "-no-audio")) no_audio = 1; + else if (!strcmp(arg, "-no-regulation")) no_regulation = 1; + else if (!strcmp(arg, "-fs")) start_fs = 1; + + else if (!strcmp(arg, "-opt")) { + set_cfg_option(argv[i+1]); + i++; + } else if (!strcmp(arg, "-conf")) { + set_cfg_option(argv[i+1]); + is_cfg_only=GF_TRUE; + i++; + } + else if (!strcmp(arg, "-ifce")) { + gf_cfg_set_key(cfg_file, "Network", "DefaultMCastInterface", argv[i+1]); + i++; + } + else if (!stricmp(arg, "-help")) { + PrintUsage(); + return 1; + } + else if (!stricmp(arg, "-noprog")) { + no_prog=1; + gf_set_progress_callback(NULL, progress_quiet); + } + else if (!stricmp(arg, "--no-save")) { + no_cfg_save=1; + } + + + /*arguments only used in non-gui mode*/ + else if (!gui_mode) { + if (arg[0] != '-') { + url_arg = arg; + } + else if (!strcmp(arg, "-out")) { + out_arg = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-fps")) { + fps = atof(argv[i+1]); + i++; + } else if (!strcmp(arg, "-avi") || !strcmp(arg, "-sha")) { + dump_mode &= 0xFFFF0000; + + if (!strcmp(arg, "-sha")) dump_mode |= DUMP_SHA1; + else dump_mode |= DUMP_AVI; + + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; + } else if (!strcmp(arg, "-rgbds")) { /*get dump in rgbds pixel format*/ + dump_mode |= DUMP_RGB_DEPTH_SHAPE; + } else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/ + dump_mode |= DUMP_RGB_DEPTH; + } else if (!strcmp(arg, "-depth")) { + dump_mode |= DUMP_DEPTH_ONLY; + } else if (!strcmp(arg, "-bmp")) { + dump_mode &= 0xFFFF0000; + dump_mode |= DUMP_BMP; + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; + } else if (!strcmp(arg, "-png")) { + dump_mode &= 0xFFFF0000; + dump_mode |= DUMP_PNG; + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; + } else if (!strcmp(arg, "-raw")) { + dump_mode &= 0xFFFF0000; + dump_mode |= DUMP_RAW; + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; + } else if (!stricmp(arg, "-scale")) { + sscanf(argv[i+1], "%f", &scale); + i++; + } + else if (!strcmp(arg, "-loop")) loop_at_end = 1; + else if (!strcmp(arg, "-bench")) bench_mode = 1; + else if (!strcmp(arg, "-vbench")) bench_mode = 2; + else if (!strcmp(arg, "-sbench")) bench_mode = 3; + else if (!strcmp(arg, "-no-addon")) enable_add_ons = GF_FALSE; + + else if (!strcmp(arg, "-pause")) pause_at_first = 1; + else if (!strcmp(arg, "-play-from")) { + play_from = atof((const char *) argv[i+1]); + } + else if (!strcmp(arg, "-speed")) { + playback_speed = FLT2FIX( atof((const char *) argv[i+1]) ); + if (playback_speed <= 0) playback_speed = FIX_ONE; + } + else if (!strcmp(arg, "-no-wnd")) user.init_flags |= GF_TERM_WINDOWLESS; + else if (!strcmp(arg, "-no-back")) user.init_flags |= GF_TERM_WINDOW_TRANSPARENT; + else if (!strcmp(arg, "-align")) { + if (argv[i+1][0]=='m') align_mode = 1; + else if (argv[i+1][0]=='b') align_mode = 2; + align_mode <<= 8; + if (argv[i+1][1]=='m') align_mode |= 1; + else if (argv[i+1][1]=='r') align_mode |= 2; + i++; + } else if (!strcmp(arg, "-fill")) { + fill_ar = GF_TRUE; + } else if (!strcmp(arg, "-show")) { + visible = 1; + } + else if (!strcmp(arg, "-exit")) auto_exit = GF_TRUE; + else if (!stricmp(arg, "-views")) { + views = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-run-for")) { + simulation_time_in_ms = atoi(argv[i+1]) * 1000; + if (!simulation_time_in_ms) + simulation_time_in_ms = 1; /*1ms*/ + i++; + } + else if (!stricmp(arg, "-com")) { + default_com = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-service")) { + initial_service_id = atoi(argv[i+1]); + i++; + } else if (!strcmp(arg, "-mem-track")) { + + } else { + fprintf(stderr, "Unrecognized option %s - skipping\n", arg); + } + } + } + if (is_cfg_only) { + gf_cfg_del(cfg_file); + fprintf(stderr, "GPAC Config updated\n"); + return 0; + } + if (dump_mode && !url_arg ) { + fprintf(stderr, "Missing argument for dump\n"); + PrintUsage(); + if (logfile) gf_fclose(logfile); + return 1; + } + + if (!gui_mode && !url_arg && (gf_cfg_get_key(cfg_file, "General", "StartupFile") != NULL)) { + gui_mode=1; + } + +#ifdef WIN32 + if (gui_mode==1) { + const char *opt; + TCHAR buffer[1024]; + DWORD res = GetCurrentDirectory(1024, buffer); + buffer[res] = 0; + opt = gf_cfg_get_key(cfg_file, "General", "ModulesDirectory"); + if (strstr(opt, buffer)) { + gui_mode=1; + } else { + gui_mode=2; + } + } +#endif + + if (gui_mode==1) { + hide_shell(1); + } + + if (!url_arg && simulation_time_in_ms) + simulation_time_in_ms += gf_sys_clock(); + +#if defined(__DARWIN__) || defined(__APPLE__) + carbon_init(); +#endif + + + if (dump_mode) rti_file = NULL; + + if (!logs_set) { + //gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_ERROR); + } + + if (rti_file) init_rti_logs(rti_file, url_arg, use_rtix); + + { + GF_SystemRTInfo rti; + if (gf_sys_get_rti(0, &rti, 0)) + fprintf(stderr, "System info: %d MB RAM - %d cores\n", (u32) (rti.physical_memory/1024/1024), rti.nb_cores); + } + + + /*setup dumping options*/ + if (dump_mode) { + user.init_flags |= GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_REGULATION /*| GF_TERM_INIT_HIDE*/; + if (visible || dump_mode==8) user.init_flags |= GF_TERM_INIT_HIDE; + gf_cfg_set_key(cfg_file, "Audio", "DriverName", "Raw Audio Output"); + no_cfg_save=GF_TRUE; + } else { + init_w = forced_width; + init_h = forced_height; + } + + user.modules = gf_modules_new(NULL, cfg_file); + if (user.modules) i = gf_modules_get_count(user.modules); + if (!i || !user.modules) { + fprintf(stderr, "Error: no modules found - exiting\n"); + if (user.modules) gf_modules_del(user.modules); + gf_cfg_del(cfg_file); + gf_sys_close(); + if (logfile) gf_fclose(logfile); + return 1; + } + fprintf(stderr, "Modules Found : %d \n", i); + + user.config = cfg_file; + user.EventProc = GPAC_EventProc; + /*dummy in this case (global vars) but MUST be non-NULL*/ + user.opaque = user.modules; + if (threading_flags) user.init_flags |= threading_flags; + if (no_audio) user.init_flags |= GF_TERM_NO_AUDIO; + if (no_regulation) user.init_flags |= GF_TERM_NO_REGULATION; + + if (threading_flags & (GF_TERM_NO_DECODER_THREAD|GF_TERM_NO_COMPOSITOR_THREAD) ) term_step = 1; + + //in dump mode we don't want to rely on system clock but on the number of samples being consumed + if (dump_mode) user.init_flags |= GF_TERM_USE_AUDIO_HW_CLOCK; + + if (bench_mode) { + gf_cfg_discard_changes(user.config); + auto_exit = GF_TRUE; + gf_cfg_set_key(user.config, "Audio", "DriverName", "Raw Audio Output"); + if (bench_mode!=2) { + gf_cfg_set_key(user.config, "Video", "DriverName", "Raw Video Output"); + gf_cfg_set_key(user.config, "RAWVideo", "RawOutput", "null"); + gf_cfg_set_key(user.config, "Compositor", "OpenGLMode", "disable"); + } else { + gf_cfg_set_key(user.config, "Video", "DisableVSync", "yes"); + } + } + + fprintf(stderr, "Loading GPAC Terminal\n"); + i = gf_sys_clock(); + term = gf_term_new(&user); + if (!term) { + fprintf(stderr, "\nInit error - check you have at least one video out and one rasterizer...\nFound modules:\n"); + list_modules(user.modules); + gf_modules_del(user.modules); + gf_cfg_discard_changes(cfg_file); + gf_cfg_del(cfg_file); + gf_sys_close(); + if (logfile) gf_fclose(logfile); + return 1; + } + fprintf(stderr, "Terminal Loaded in %d ms\n", gf_sys_clock()-i); + + if (bench_mode) { + display_rti = 2; + gf_term_set_option(term, GF_OPT_VIDEO_BENCH, (bench_mode==3) ? 2 : 1); + if (bench_mode==1) bench_mode=2; + } + + if (dump_mode) { +// gf_term_set_option(term, GF_OPT_VISIBLE, 0); + if (fill_ar) gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN); + } else { + /*check video output*/ + str = gf_cfg_get_key(cfg_file, "Video", "DriverName"); + if (!bench_mode && !strcmp(str, "Raw Video Output")) fprintf(stderr, "WARNING: using raw output video (memory only) - no display used\n"); + /*check audio output*/ + str = gf_cfg_get_key(cfg_file, "Audio", "DriverName"); + if (!str || !strcmp(str, "No Audio Output Available")) fprintf(stderr, "WARNING: no audio output available - make sure no other program is locking the sound card\n"); + + str = gf_cfg_get_key(cfg_file, "General", "NoMIMETypeFetch"); + no_mime_check = (str && !stricmp(str, "yes")) ? 1 : 0; + } + + str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Enabled"); + if (str && !strcmp(str, "yes")) { + str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Name"); + if (str) fprintf(stderr, "HTTP Proxy %s enabled\n", str); + } + + if (rti_file) { + str = gf_cfg_get_key(cfg_file, "General", "RTIRefreshPeriod"); + if (str) { + rti_update_time_ms = atoi(str); + } else { + gf_cfg_set_key(cfg_file, "General", "RTIRefreshPeriod", "200"); + } + UpdateRTInfo("At GPAC load time\n"); + } + + Run = 1; + + if (dump_mode) { + if (!nb_times) { + times[0] = 0; + nb_times++; + } + dump_file(url_arg, out_arg, dump_mode, fps, forced_width, forced_height, scale, times, nb_times); + Run = 0; + } + else if (views) { + } + /*connect if requested*/ + else if (!gui_mode && url_arg) { + char *ext; + + strcpy(the_url, url_arg); + ext = strrchr(the_url, '.'); + if (ext && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) { + GF_Err e = GF_OK; + fprintf(stderr, "Opening Playlist %s\n", the_url); + + strcpy(pl_path, the_url); + /*this is not clean, we need to have a plugin handle playlist for ourselves*/ + if (!strncmp("http:", the_url, 5)) { + GF_DownloadSession *sess = gf_dm_sess_new(term->downloader, the_url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e); + if (sess) { + e = gf_dm_sess_process(sess); + if (!e) strcpy(the_url, gf_dm_sess_get_cache_name(sess)); + gf_dm_sess_del(sess); + } + } + + playlist = e ? NULL : gf_fopen(the_url, "rt"); + readonly_playlist = 1; + if (playlist) { + if (1 > fscanf(playlist, "%s", the_url)) + fprintf(stderr, "Cannot read any URL from playlist\n"); + else { + fprintf(stderr, "Opening URL %s\n", the_url); + gf_term_connect_with_path(term, the_url, pl_path); + } + } else { + if (e) + fprintf(stderr, "Failed to open playlist %s: %s\n", the_url, gf_error_to_string(e) ); + fprintf(stderr, "Hit 'h' for help\n\n"); + } + } else { + fprintf(stderr, "Opening URL %s\n", the_url); + if (pause_at_first) fprintf(stderr, "[Status: Paused]\n"); + gf_term_connect_from_time(term, the_url, (u64) (play_from*1000), pause_at_first); + } + } else { + fprintf(stderr, "Hit 'h' for help\n\n"); + str = gf_cfg_get_key(cfg_file, "General", "StartupFile"); + if (str) { + strcpy(the_url, "MP4Client "GPAC_FULL_VERSION); + gf_term_connect(term, str); + startup_file = 1; + is_connected = 1; + } + } + if (gui_mode==2) gui_mode=0; + + if (start_fs) gf_term_set_option(term, GF_OPT_FULLSCREEN, 1); + + if (views) { + char szTemp[4046]; + sprintf(szTemp, "views://%s", views); + gf_term_connect(term, szTemp); + } + if (bench_mode) { + rti_update_time_ms = 500; + bench_mode_start = gf_sys_clock(); + } + + + while (Run) { + + /*we don't want getchar to block*/ + if ((gui_mode==1) || !gf_prompt_has_input()) { + if (reload) { + reload = 0; + gf_term_disconnect(term); + gf_term_connect(term, startup_file ? gf_cfg_get_key(cfg_file, "General", "StartupFile") : the_url); + } + if (restart && gf_term_get_option(term, GF_OPT_IS_OVER)) { + restart = 0; + gf_term_play_from_time(term, 0, 0); + } + if (request_next_playlist_item) { + c = '\n'; + request_next_playlist_item = 0; + goto force_input; + } + + if (default_com && is_connected) { + gf_term_scene_update(term, NULL, default_com); + default_com = NULL; + } + if (initial_service_id && is_connected) { + GF_ObjectManager *root_od = gf_term_get_root_object(term); + if (root_od) { + gf_term_select_service(term, root_od, initial_service_id); + initial_service_id = 0; + } + } + + if (!use_rtix || display_rti) UpdateRTInfo(NULL); + if (term_step) { + gf_term_process_step(term); + } else { + gf_sleep(rti_update_time_ms); + } + if (auto_exit && eos_seen && gf_term_get_option(term, GF_OPT_IS_OVER)) { + Run = GF_FALSE; + } + + /*sim time*/ + if (simulation_time_in_ms + && ( (gf_term_get_time_in_ms(term)>simulation_time_in_ms) || (!url_arg && gf_sys_clock()>simulation_time_in_ms)) + ) { + Run = GF_FALSE; + } + continue; + } + c = gf_prompt_get_char(); + +force_input: + switch (c) { + case 'q': + { + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_QUIT; + gf_term_send_event(term, &evt); + } +// Run = 0; + break; + case 'X': + exit(0); + break; + case 'Q': + break; + case 'o': + startup_file = 0; + gf_term_disconnect(term); + fprintf(stderr, "Enter the absolute URL\n"); + if (1 > scanf("%s", the_url)) { + fprintf(stderr, "Cannot read absolute URL, aborting\n"); + break; + } + if (rti_file) init_rti_logs(rti_file, the_url, use_rtix); + gf_term_connect(term, the_url); + break; + case 'O': + gf_term_disconnect(term); + fprintf(stderr, "Enter the absolute URL to the playlist\n"); + if (1 > scanf("%s", the_url)) { + fprintf(stderr, "Cannot read the absolute URL, aborting.\n"); + break; + } + playlist = gf_fopen(the_url, "rt"); + if (playlist) { + if (1 > fscanf(playlist, "%s", the_url)) { + fprintf(stderr, "Cannot read any URL from playlist, aborting.\n"); + gf_fclose( playlist); + break; + } + fprintf(stderr, "Opening URL %s\n", the_url); + gf_term_connect(term, the_url); + } + break; + case '\n': + case 'N': + if (playlist) { + int res; + gf_term_disconnect(term); + + res = fscanf(playlist, "%s", the_url); + if ((res == EOF) && loop_at_end) { + fseek(playlist, 0, SEEK_SET); + res = fscanf(playlist, "%s", the_url); + } + if (res == EOF) { + fprintf(stderr, "No more items - exiting\n"); + Run = 0; + } else { + fprintf(stderr, "Opening URL %s\n", the_url); + gf_term_connect_with_path(term, the_url, pl_path); + } + } + break; + case 'P': + if (playlist) { + u32 count; + gf_term_disconnect(term); + if (1 > scanf("%u", &count)) { + fprintf(stderr, "Cannot read number, aborting.\n"); + break; + } + while (count) { + if (fscanf(playlist, "%s", the_url)) { + fprintf(stderr, "Failed to read line, aborting\n"); + break; + } + count--; + } + fprintf(stderr, "Opening URL %s\n", the_url); + gf_term_connect(term, the_url); + } + break; + case 'r': + if (is_connected) + reload = 1; + break; + + case 'D': + if (is_connected) gf_term_disconnect(term); + break; + + case 'p': + if (is_connected) { + Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE); + fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused"); + gf_term_set_option(term, GF_OPT_PLAY_STATE, is_pause ? GF_STATE_PLAYING : GF_STATE_PAUSED); + } + break; + case 's': + if (is_connected) { + gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE); + fprintf(stderr, "Step time: "); + PrintTime(gf_term_get_time_in_ms(term)); + fprintf(stderr, "\n"); + } + break; + + case 'z': + case 'T': + if (!CanSeek || (Duration<=2000)) { + fprintf(stderr, "scene not seekable\n"); + } else { + Double res; + s32 seekTo; + fprintf(stderr, "Duration: "); + PrintTime(Duration); + res = gf_term_get_time_in_ms(term); + if (c=='z') { + res *= 100; + res /= (s64)Duration; + fprintf(stderr, " (current %.2f %%)\nEnter Seek percentage:\n", res); + if (scanf("%d", &seekTo) == 1) { + if (seekTo > 100) seekTo = 100; + res = (Double)(s64)Duration; + res /= 100; + res *= seekTo; + gf_term_play_from_time(term, (u64) (s64) res, 0); + } + } else { + u32 r, h, m, s; + fprintf(stderr, " - Current Time: "); + PrintTime((u64) res); + fprintf(stderr, "\nEnter seek time (Format: s, m:s or h:m:s):\n"); + h = m = s = 0; + r =scanf("%d:%d:%d", &h, &m, &s); + if (r==2) { + s = m; + m = h; + h = 0; + } + else if (r==1) { + s = h; + m = h = 0; + } + + if (r && (r<=3)) { + u64 time = h*3600 + m*60 + s; + gf_term_play_from_time(term, time*1000, 0); + } + } + } + break; + + case 't': + { + if (is_connected) { + fprintf(stderr, "Current Time: "); + PrintTime(gf_term_get_time_in_ms(term)); + fprintf(stderr, " - Duration: "); + PrintTime(Duration); + fprintf(stderr, "\n"); + } + } + break; + case 'w': + if (is_connected) PrintWorldInfo(term); + break; + case 'v': + if (is_connected) PrintODList(term, NULL, 0, 0, "Root"); + break; + case 'i': + if (is_connected) { + u32 ID; + fprintf(stderr, "Enter OD ID (0 for main OD): "); + fflush(stderr); + if (scanf("%ud", &ID) == 1) { + ViewOD(term, ID, (u32)-1, NULL); + } else { + char str_url[GF_MAX_PATH]; + if (scanf("%s", str_url) == 1) + ViewOD(term, 0, (u32)-1, str_url); + } + } + break; + case 'j': + if (is_connected) { + u32 num; + do { + fprintf(stderr, "Enter OD number (0 for main OD): "); + fflush(stderr); + } while( 1 > scanf("%ud", &num)); + ViewOD(term, (u32)-1, num, NULL); + } + break; + case 'b': + if (is_connected) ViewODs(term, 1); + break; + + case 'm': + if (is_connected) ViewODs(term, 0); + break; + + case 'l': + list_modules(user.modules); + break; + + case 'n': + if (is_connected) set_navigation(); + break; + case 'x': + if (is_connected) gf_term_set_option(term, GF_OPT_NAVIGATION_TYPE, 0); + break; + + case 'd': + if (is_connected) { + GF_ObjectManager *odm = NULL; + char radname[GF_MAX_PATH], *sExt; + GF_Err e; + u32 i, count, odid; + Bool xml_dump, std_out; + radname[0] = 0; + do { + fprintf(stderr, "Enter Inline OD ID if any or 0 : "); + fflush(stderr); + } while( 1 > scanf("%ud", &odid)); + if (odid) { + GF_ObjectManager *root_odm = gf_term_get_root_object(term); + if (!root_odm) break; + count = gf_term_get_object_count(term, root_odm); + for (i=0; iobjectDescriptorID==odid) break; + } + odm = NULL; + } + } + do { + fprintf(stderr, "Enter file radical name (+\'.x\' for XML dumping) - \"std\" for stderr: "); + fflush(stderr); + } while( 1 > scanf("%s", radname)); + sExt = strrchr(radname, '.'); + xml_dump = 0; + if (sExt) { + if (!stricmp(sExt, ".x")) xml_dump = 1; + sExt[0] = 0; + } + std_out = strnicmp(radname, "std", 3) ? 0 : 1; + e = gf_term_dump_scene(term, std_out ? NULL : radname, NULL, xml_dump, 0, odm); + fprintf(stderr, "Dump done (%s)\n", gf_error_to_string(e)); + } + break; + + case 'c': + PrintGPACConfig(); + break; + case '3': + { + Bool use_3d = !gf_term_get_option(term, GF_OPT_USE_OPENGL); + if (gf_term_set_option(term, GF_OPT_USE_OPENGL, use_3d)==GF_OK) { + fprintf(stderr, "Using %s for 2D drawing\n", use_3d ? "OpenGL" : "2D rasterizer"); + } + } + break; + case 'k': + { + Bool opt = gf_term_get_option(term, GF_OPT_STRESS_MODE); + opt = !opt; + fprintf(stderr, "Turning stress mode %s\n", opt ? "on" : "off"); + gf_term_set_option(term, GF_OPT_STRESS_MODE, opt); + } + break; + case '4': + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3); + break; + case '5': + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9); + break; + case '6': + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN); + break; + case '7': + gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP); + break; + + case 'C': + switch (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)) { + case GF_MEDIA_CACHE_DISABLED: + gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_ENABLED); + break; + case GF_MEDIA_CACHE_ENABLED: + gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_DISABLED); + break; + case GF_MEDIA_CACHE_RUNNING: + fprintf(stderr, "Streaming Cache is running - please stop it first\n"); + continue; + } + switch (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)) { + case GF_MEDIA_CACHE_ENABLED: + fprintf(stderr, "Streaming Cache Enabled\n"); + break; + case GF_MEDIA_CACHE_DISABLED: + fprintf(stderr, "Streaming Cache Disabled\n"); + break; + case GF_MEDIA_CACHE_RUNNING: + fprintf(stderr, "Streaming Cache Running\n"); + break; + } + break; + case 'S': + case 'A': + if (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)==GF_MEDIA_CACHE_RUNNING) { + gf_term_set_option(term, GF_OPT_MEDIA_CACHE, (c=='S') ? GF_MEDIA_CACHE_DISABLED : GF_MEDIA_CACHE_DISCARD); + fprintf(stderr, "Streaming Cache stopped\n"); + } else { + fprintf(stderr, "Streaming Cache not running\n"); + } + break; + case 'R': + display_rti = !display_rti; + ResetCaption(); + break; + case 'F': + if (display_rti) display_rti = 0; + else display_rti = 2; + ResetCaption(); + break; + + case 'u': + { + GF_Err e; + char szCom[8192]; + fprintf(stderr, "Enter command to send:\n"); + fflush(stdin); + szCom[0] = 0; + if (1 > scanf("%[^\t\n]", szCom)) { + fprintf(stderr, "Cannot read command to send, aborting.\n"); + break; + } + e = gf_term_scene_update(term, NULL, szCom); + if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); + } + break; + case 'e': + { + GF_Err e; + char jsCode[8192]; + fprintf(stderr, "Enter JavaScript code to evaluate:\n"); + fflush(stdin); + jsCode[0] = 0; + if (1 > scanf("%[^\t\n]", jsCode)) { + fprintf(stderr, "Cannot read code to evaluate, aborting.\n"); + break; + } + e = gf_term_scene_update(term, "application/ecmascript", jsCode); + if (e) fprintf(stderr, "Processing JS code failed: %s\n", gf_error_to_string(e)); + } + break; + + case 'L': + { + char szLog[1024], *cur_logs; + cur_logs = gf_log_get_tools_levels(); + fprintf(stderr, "Enter new log level (current tools %s):\n", cur_logs); + gf_free(cur_logs); + if (scanf("%s", szLog) < 1) { + fprintf(stderr, "Cannot read new log level, aborting.\n"); + break; + } + gf_log_modify_tools_levels(szLog); + } + break; + + case 'g': + { + GF_SystemRTInfo rti; + gf_sys_get_rti(rti_update_time_ms, &rti, 0); + fprintf(stderr, "GPAC allocated memory "LLD"\n", rti.gpac_memory); + } + break; + case 'M': + { + u32 size; + do { + fprintf(stderr, "Enter new video cache memory in kBytes (current %ud):\n", gf_term_get_option(term, GF_OPT_VIDEO_CACHE_SIZE)); + } while (1 > scanf("%ud", &size)); + gf_term_set_option(term, GF_OPT_VIDEO_CACHE_SIZE, size); + } + break; + + case 'H': + { + u32 http_bitrate = gf_term_get_option(term, GF_OPT_HTTP_MAX_RATE); + do { + fprintf(stderr, "Enter new http bitrate in bps (0 for none) - current limit: %d\n", http_bitrate); + } while (1 > scanf("%ud", &http_bitrate)); + + gf_term_set_option(term, GF_OPT_HTTP_MAX_RATE, http_bitrate); + } + break; + + case 'E': + gf_term_set_option(term, GF_OPT_RELOAD_CONFIG, 1); + break; + + case 'B': + switch_bench(!bench_mode); + break; + + case 'Y': + { + char szOpt[8192]; + fprintf(stderr, "Enter option to set (Section:Name=Value):\n"); + fflush(stdin); + szOpt[0] = 0; + if (1 > scanf("%[^\t\n]", szOpt)) { + fprintf(stderr, "Cannot read option\n"); + break; + } + set_cfg_option(szOpt); + } + break; + + /*extract to PNG*/ + case 'Z': + { + char szFileName[100]; + u32 nb_pass, nb_views, offscreen_view = 0; + GF_VideoSurface fb; + GF_Err e; + nb_pass = 1; + nb_views = gf_term_get_option(term, GF_OPT_NUM_STEREO_VIEWS); + if (nb_views>1) { + fprintf(stderr, "Auto-stereo mode detected - type number of view to dump (0 is main output, 1 to %d offscreen view, %d for all offscreen, %d for all offscreen and main)\n", nb_views, nb_views+1, nb_views+2); + if (scanf("%d", &offscreen_view) != 1) { + offscreen_view = 0; + } + if (offscreen_view==nb_views+1) { + offscreen_view = 1; + nb_pass = nb_views; + } + else if (offscreen_view==nb_views+2) { + offscreen_view = 0; + nb_pass = nb_views+1; + } + } + while (nb_pass) { + nb_pass--; + if (offscreen_view) { + sprintf(szFileName, "view%d_dump.png", offscreen_view); + e = gf_term_get_offscreen_buffer(term, &fb, offscreen_view-1, 0); + } else { + sprintf(szFileName, "gpac_video_dump_"LLU".png", gf_net_get_utc() ); + e = gf_term_get_screen_buffer(term, &fb); + } + offscreen_view++; + if (e) { + fprintf(stderr, "Error dumping screen buffer %s\n", gf_error_to_string(e) ); + nb_pass = 0; + } else { +#ifndef GPAC_DISABLE_AV_PARSERS + u32 dst_size = fb.width*fb.height*4; + char *dst = (char*)gf_malloc(sizeof(char)*dst_size); + + e = gf_img_png_enc(fb.video_buffer, fb.width, fb.height, fb.pitch_y, fb.pixel_format, dst, &dst_size); + if (e) { + fprintf(stderr, "Error encoding PNG %s\n", gf_error_to_string(e) ); + nb_pass = 0; + } else { + FILE *png = gf_fopen(szFileName, "wb"); + if (!png) { + fprintf(stderr, "Error writing file %s\n", szFileName); + nb_pass = 0; + } else { + gf_fwrite(dst, dst_size, 1, png); + gf_fclose(png); + fprintf(stderr, "Dump to %s\n", szFileName); + } + } + if (dst) gf_free(dst); + gf_term_release_screen_buffer(term, &fb); +#endif //GPAC_DISABLE_AV_PARSERS + } + } + fprintf(stderr, "Done: %s\n", szFileName); + } + break; + + case 'G': + { + GF_ObjectManager *root_od, *odm; + u32 index; + char szOpt[8192]; + fprintf(stderr, "Enter 0-based index of object to select or service ID:\n"); + fflush(stdin); + szOpt[0] = 0; + if (1 > scanf("%[^\t\n]", szOpt)) { + fprintf(stderr, "Cannot read OD ID\n"); + break; + } + index = atoi(szOpt); + odm = NULL; + root_od = gf_term_get_root_object(term); + if (root_od) { + odm = gf_term_get_object(term, root_od, index); + if (odm) { + gf_term_select_object(term, odm); + } else { + fprintf(stderr, "Cannot find object at index %d - trying with serviceID\n", index); + gf_term_select_service(term, root_od, index); + } + } + } + break; + + case 'h': + PrintHelp(); + break; + default: + break; + } + } + + if (bench_mode) { + PrintAVInfo(GF_TRUE); + } + + /*FIXME: we have an issue in cleaning up after playing in bench mode and run-for 0 (buildbot tests). We for now disable error checks after run-for is done*/ + if (simulation_time_in_ms) { + gf_log_set_strict_error(0); + } + + + i = gf_sys_clock(); + gf_term_disconnect(term); + if (rti_file) UpdateRTInfo("Disconnected\n"); + + fprintf(stderr, "Deleting terminal... "); + if (playlist) gf_fclose(playlist); + +#if defined(__DARWIN__) || defined(__APPLE__) + carbon_uninit(); +#endif + + gf_term_del(term); + fprintf(stderr, "done (in %d ms) - ran for %d ms\n", gf_sys_clock() - i, gf_sys_clock()); + + fprintf(stderr, "GPAC cleanup ...\n"); + gf_modules_del(user.modules); + + if (no_cfg_save) + gf_cfg_discard_changes(cfg_file); + + gf_cfg_del(cfg_file); + + gf_sys_close(); + + if (rti_logs) gf_fclose(rti_logs); + if (logfile) gf_fclose(logfile); + + if (gui_mode) { + hide_shell(2); + } + +#ifdef GPAC_MEMORY_TRACKING + if (enable_mem_tracker && (gf_memory_size() || gf_file_handles_count() )) { + gf_memory_print(); + return 2; + } +#endif + + return 0; +} + +static GF_ObjectManager *video_odm = NULL; +static GF_ObjectManager *audio_odm = NULL; +static GF_ObjectManager *scene_odm = NULL; +static u32 last_odm_count = 0; +void PrintAVInfo(Bool final) +{ + GF_MediaInfo a_odi, v_odi, s_odi; + Double avg_dec_time=0; + u32 tot_time=0; + Bool print_codecs = final; + + if (scene_odm) { + GF_ObjectManager *root_odm = gf_term_get_root_object(term); + u32 count = gf_term_get_object_count(term, root_odm); + if (last_odm_count != count) { + last_odm_count = count; + scene_odm = NULL; + } + } + if (!video_odm && !audio_odm && !scene_odm) { + u32 count, i; + GF_ObjectManager *root_odm = root_odm = gf_term_get_root_object(term); + if (!root_odm) return; + + if (gf_term_get_object_info(term, root_odm, &v_odi)==GF_OK) { + if (!scene_odm && (v_odi.generated_scene== 0)) { + scene_odm = root_odm; + } + } + + count = gf_term_get_object_count(term, root_odm); + for (i=0; i1) || v_odi.direct_video_memory) ) { + video_odm = odm; + } + else if (!audio_odm && (v_odi.od_type == GF_STREAM_AUDIO)) { + audio_odm = odm; + } + else if (!scene_odm && (v_odi.od_type == GF_STREAM_SCENE)) { + scene_odm = odm; + } + } + } + } + + if (0 && bench_buffer) { + fprintf(stderr, "Buffering %d %% ", bench_buffer-1); + return; + } + + if (video_odm) { + if (gf_term_get_object_info(term, video_odm, &v_odi)!= GF_OK) { + video_odm = NULL; + return; + } + avg_dec_time = 0; + if (v_odi.nb_dec_frames && v_odi.total_dec_time) { + avg_dec_time = (Float) 1000000 * v_odi.nb_dec_frames; + avg_dec_time /= v_odi.total_dec_time; + } + } + if (print_codecs && audio_odm) { + gf_term_get_object_info(term, audio_odm, &a_odi); + } + if ((print_codecs || !video_odm) && scene_odm) { + gf_term_get_object_info(term, scene_odm, &s_odi); + } + + if (final) { + tot_time = gf_sys_clock() - bench_mode_start; + fprintf(stderr, " \r"); + fprintf(stderr, "************** Bench Mode Done in %d ms ********************\n", tot_time); + if (bench_mode==3) fprintf(stderr, "** Systems layer only (no decoding) **\n"); + + if (!video_odm) { + u32 nb_frames_drawn; + Double FPS = gf_term_get_simulation_frame_rate(term, &nb_frames_drawn); + fprintf(stderr, "Drawn %d frames FPS %.2f (simulation FPS %.2f) - duration %d ms\n", nb_frames_drawn, ((Float)nb_frames_drawn*1000)/tot_time,(Float) FPS, gf_term_get_time_in_ms(term) ); + } + } + if (print_codecs) { + if (video_odm) { + fprintf(stderr, "%s %dx%d sar=%d:%d duration %.2fs\n", v_odi.codec_name, v_odi.width, v_odi.height, v_odi.par ? (v_odi.par>>16)&0xFF : 1, v_odi.par ? (v_odi.par)&0xFF : 1, v_odi.duration); + if (final) { + u32 dec_run_time = v_odi.last_frame_time - v_odi.first_frame_time; + if (!dec_run_time) dec_run_time = 1; + if (v_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*v_odi.current_time / v_odi.duration ) ); + fprintf(stderr, "%d frames FPS %.2f (max %d us/f) rate avg %d max %d", v_odi.nb_dec_frames, ((Float)v_odi.nb_dec_frames*1000) / dec_run_time, v_odi.max_dec_time, (u32) v_odi.avg_bitrate/1000, (u32) v_odi.max_bitrate/1000); + if (v_odi.nb_dropped) { + fprintf(stderr, " (Error during bench: %d frames drop)", v_odi.nb_dropped); + } + fprintf(stderr, "\n"); + } + } + if (audio_odm) { + fprintf(stderr, "%s SR %d num channels %d bpp %d duration %.2fs\n", a_odi.codec_name, a_odi.sample_rate, a_odi.num_channels, a_odi.bits_per_sample, a_odi.duration); + if (final) { + u32 dec_run_time = a_odi.last_frame_time - a_odi.first_frame_time; + if (!dec_run_time) dec_run_time = 1; + if (a_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*a_odi.current_time / a_odi.duration ) ); + fprintf(stderr, "%d frames (ms/f %.2f avg %.2f max) rate avg %d max %d", a_odi.nb_dec_frames, ((Float)dec_run_time)/a_odi.nb_dec_frames, a_odi.max_dec_time/1000.0, (u32) a_odi.avg_bitrate/1000, (u32) a_odi.max_bitrate/1000); + if (a_odi.nb_dropped) { + fprintf(stderr, " (Error during bench: %d frames drop)", a_odi.nb_dropped); + } + fprintf(stderr, "\n"); + } + } + if (scene_odm) { + u32 w, h; + gf_term_get_visual_output_size(term, &w, &h); + fprintf(stderr, "%s scene size %dx%d rastered to %dx%d duration %.2fs\n", s_odi.codec_name, s_odi.width, s_odi.height, w, h, s_odi.duration); + if (final) { + if (s_odi.nb_dec_frames>2 && s_odi.total_dec_time) { + u32 dec_run_time = s_odi.last_frame_time - s_odi.first_frame_time; + if (!dec_run_time) dec_run_time = 1; + fprintf(stderr, "%d frames FPS %.2f (max %d us/f) rate avg %d max %d", s_odi.nb_dec_frames, ((Float)s_odi.nb_dec_frames*1000) / dec_run_time, s_odi.max_dec_time, (u32) s_odi.avg_bitrate/1000, (u32) s_odi.max_bitrate/1000); + fprintf(stderr, "\n"); + } else { + u32 nb_frames_drawn; + Double FPS = gf_term_get_simulation_frame_rate(term, &nb_frames_drawn); + tot_time = gf_sys_clock() - bench_mode_start; + FPS = gf_term_get_framerate(term, 0); + fprintf(stderr, "%d frames FPS %.2f (abs %.2f)\n", nb_frames_drawn, (1000.0*nb_frames_drawn / tot_time), FPS); + } + } + } + if (final) { + fprintf(stderr, "**********************************************************\n\n"); + return; + } + } + + if (video_odm) { + tot_time = v_odi.last_frame_time - v_odi.first_frame_time; + if (!tot_time) tot_time=1; + if (v_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*v_odi.current_time / v_odi.duration ) ); + fprintf(stderr, "%d f FPS %.2f (%.2f ms max) rate %d ", v_odi.nb_dec_frames, ((Float)v_odi.nb_dec_frames*1000) / tot_time, v_odi.max_dec_time/1000.0, (u32) v_odi.instant_bitrate/1000); + } + else if (scene_odm) { + + avg_dec_time = 0; + if (s_odi.nb_dec_frames>2 && s_odi.total_dec_time) { + avg_dec_time = (Float) 1000000 * s_odi.nb_dec_frames; + avg_dec_time /= s_odi.total_dec_time; + if (s_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*s_odi.current_time / s_odi.duration ) ); + fprintf(stderr, "%d f %.2f (%d us max) - rate %d ", s_odi.nb_dec_frames, avg_dec_time, s_odi.max_dec_time, (u32) s_odi.instant_bitrate/1000); + } else { + u32 nb_frames_drawn; + Double FPS = gf_term_get_simulation_frame_rate(term, &nb_frames_drawn); + tot_time = gf_sys_clock() - bench_mode_start; + FPS = gf_term_get_framerate(term, 1); + fprintf(stderr, "%d f FPS %.2f (abs %.2f) ", nb_frames_drawn, (1000.0*nb_frames_drawn / tot_time), FPS); + } + } + else if (audio_odm) { + if (!print_codecs) { + gf_term_get_object_info(term, audio_odm, &a_odi); + } + tot_time = a_odi.last_frame_time - a_odi.first_frame_time; + if (!tot_time) tot_time=1; + if (a_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*a_odi.current_time / a_odi.duration ) ); + fprintf(stderr, "%d frames (ms/f %.2f avg %.2f max)", a_odi.nb_dec_frames, ((Float)tot_time)/a_odi.nb_dec_frames, a_odi.max_dec_time/1000.0); + } +} + +void PrintWorldInfo(GF_Terminal *term) +{ + u32 i; + const char *title; + GF_List *descs; + descs = gf_list_new(); + title = gf_term_get_world_info(term, NULL, descs); + if (!title && !gf_list_count(descs)) { + fprintf(stderr, "No World Info available\n"); + } else { + fprintf(stderr, "\t%s\n", title ? title : "No title available"); + for (i=0; iServiceID) fprintf(stderr, "Service ID %d ", odi.od->ServiceID); + if (odi.media_url) { + fprintf(stderr, "%s\n", odi.media_url); + } else { + fprintf(stderr, "OD ID %d\n", odi.od->objectDescriptorID); + } + + szIndent[indent]=' '; + szIndent[indent+1]=0; + indent++; + + count = gf_term_get_object_count(term, root_odm); + for (i=0; iobjectDescriptorID); + } + fprintf(stderr, " - %s", (odi.od_type==GF_STREAM_VISUAL) ? "Video" : (odi.od_type==GF_STREAM_AUDIO) ? "Audio" : "Systems"); + if (odi.od && odi.od->ServiceID) fprintf(stderr, " - Service ID %d", odi.od->ServiceID); + fprintf(stderr, "\n"); + break; + } + } + } +} + +void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number, const char *szURL) +{ + GF_MediaInfo odi; + u32 i, j, count, d_enum,id; + GF_Err e; + NetStatCommand com; + GF_ObjectManager *odm, *root_odm = gf_term_get_root_object(term); + if (!root_odm) return; + + odm = NULL; + if (!szURL && ((!OD_ID && (number == (u32)-1)) || ((OD_ID == (u32)(-1)) && !number))) { + odm = root_odm; + if ((gf_term_get_object_info(term, odm, &odi) != GF_OK)) odm=NULL; + } else { + count = gf_term_get_object_count(term, root_odm); + for (i=0; iobjectDescriptorID == OD_ID)) break; + else if (i == (u32)(number-1)) break; + } + odm = NULL; + } + } + if (!odm) { + if (szURL) fprintf(stderr, "cannot find OD for URL %s\n", szURL); + if (number == (u32)-1) fprintf(stderr, "cannot find OD with ID %d\n", OD_ID); + else fprintf(stderr, "cannot find OD with number %d\n", number); + return; + } + if (!odi.od) { + if (number == (u32)-1) fprintf(stderr, "Object %d not attached yet\n", OD_ID); + else fprintf(stderr, "Object #%d not attached yet\n", number); + return; + } + + if (!odi.od) { + fprintf(stderr, "Service not attached\n"); + return; + } + + if (odi.od->tag==GF_ODF_IOD_TAG) { + fprintf(stderr, "InitialObjectDescriptor %d\n", odi.od->objectDescriptorID); + fprintf(stderr, "Profiles and Levels: Scene %x - Graphics %x - Visual %x - Audio %x - OD %x\n", + odi.scene_pl, odi.graphics_pl, odi.visual_pl, odi.audio_pl, odi.OD_pl); + fprintf(stderr, "Inline Profile Flag %d\n", odi.inline_pl); + } else { + fprintf(stderr, "ObjectDescriptor %d\n", odi.od->objectDescriptorID); + } + + fprintf(stderr, "Object Duration: "); + if (odi.duration) { + PrintTime((u32) (odi.duration*1000)); + } else { + fprintf(stderr, "unknown"); + } + fprintf(stderr, "\n"); + + fprintf(stderr, "Service Handler: %s\n", odi.service_handler); + fprintf(stderr, "Service URL: %s\n", odi.service_url); + + if (odi.codec_name) { + Float avg_dec_time; + switch (odi.od_type) { + case GF_STREAM_VISUAL: + fprintf(stderr, "Video Object: Width %d - Height %d\r\n", odi.width, odi.height); + fprintf(stderr, "Media Codec: %s\n", odi.codec_name); + if (odi.par) fprintf(stderr, "Pixel Aspect Ratio: %d:%d\n", (odi.par>>16)&0xFF, (odi.par)&0xFF); + break; + case GF_STREAM_AUDIO: + fprintf(stderr, "Audio Object: Sample Rate %d - %d channels\r\n", odi.sample_rate, odi.num_channels); + fprintf(stderr, "Media Codec: %s\n", odi.codec_name); + break; + case GF_STREAM_SCENE: + case GF_STREAM_PRIVATE_SCENE: + if (odi.width && odi.height) { + fprintf(stderr, "Scene Description - Width %d - Height %d\n", odi.width, odi.height); + } else { + fprintf(stderr, "Scene Description - no size specified\n"); + } + fprintf(stderr, "Scene Codec: %s\n", odi.codec_name); + break; + case GF_STREAM_TEXT: + if (odi.width && odi.height) { + fprintf(stderr, "Text Object: Width %d - Height %d\n", odi.width, odi.height); + } else { + fprintf(stderr, "Text Object: No size specified\n"); + } + fprintf(stderr, "Text Codec %s\n", odi.codec_name); + break; + } + + avg_dec_time = 0; + if (odi.nb_dec_frames) { + avg_dec_time = (Float) odi.total_dec_time; + avg_dec_time /= odi.nb_dec_frames; + } + fprintf(stderr, "\tBitrate over last second: %d kbps\n\tMax bitrate over one second: %d kbps\n\tAverage Decoding Time %.2f us %d max)\n\tTotal decoded frames %d\n", + (u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time, odi.nb_dec_frames); + } + if (odi.protection) fprintf(stderr, "Encrypted Media%s\n", (odi.protection==2) ? " NOT UNLOCKED" : ""); + + count = gf_list_count(odi.od->ESDescriptors); + fprintf(stderr, "%d streams in OD\n", count); + for (i=0; iESDescriptors, i); + + fprintf(stderr, "\nStream ID %d - Clock ID %d\n", esd->ESID, esd->OCRESID); + if (esd->dependsOnESID) fprintf(stderr, "\tDepends on Stream ID %d for decoding\n", esd->dependsOnESID); + + switch (esd->decoderConfig->streamType) { + case GF_STREAM_OD: + fprintf(stderr, "\tOD Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + case GF_STREAM_OCR: + fprintf(stderr, "\tOCR Stream\n"); + break; + case GF_STREAM_SCENE: + fprintf(stderr, "\tScene Description Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + case GF_STREAM_VISUAL: + fprintf(stderr, "\tVisual Stream - media type: %s", gf_esd_get_textual_description(esd)); + break; + case GF_STREAM_AUDIO: + fprintf(stderr, "\tAudio Stream - media type: %s", gf_esd_get_textual_description(esd)); + break; + case GF_STREAM_MPEG7: + fprintf(stderr, "\tMPEG-7 Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + case GF_STREAM_IPMP: + fprintf(stderr, "\tIPMP Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + case GF_STREAM_OCI: + fprintf(stderr, "\tOCI Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + case GF_STREAM_MPEGJ: + fprintf(stderr, "\tMPEGJ Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + case GF_STREAM_INTERACT: + fprintf(stderr, "\tUser Interaction Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + case GF_STREAM_TEXT: + fprintf(stderr, "\tStreaming Text Stream - version %d\n", esd->decoderConfig->objectTypeIndication); + break; + default: + fprintf(stderr, "\tUnknown Stream\n"); + break; + } + + fprintf(stderr, "\tBuffer Size %d\n\tAverage Bitrate %d bps\n\tMaximum Bitrate %d bps\n", esd->decoderConfig->bufferSizeDB, esd->decoderConfig->avgBitrate, esd->decoderConfig->maxBitrate); + if (esd->slConfig->predefined==SLPredef_SkipSL) { + fprintf(stderr, "\tNot using MPEG-4 Synchronization Layer\n"); + } else { + fprintf(stderr, "\tStream Clock Resolution %d\n", esd->slConfig->timestampResolution); + } + if (esd->URLString) fprintf(stderr, "\tStream Location: %s\n", esd->URLString); + + /*check language*/ + if (esd->langDesc) { + s32 lang_idx; + char lan[4]; + lan[0] = esd->langDesc->langCode>>16; + lan[1] = (esd->langDesc->langCode>>8)&0xFF; + lan[2] = (esd->langDesc->langCode)&0xFF; + lan[3] = 0; + + lang_idx = gf_lang_find(lan); + if (lang_idx>=0) { + fprintf(stderr, "\tStream Language: %s\n", gf_lang_get_name(lang_idx)); + } + } + } + fprintf(stderr, "\n"); + /*check OCI (not everything interests us) - FIXME: support for unicode*/ + count = gf_list_count(odi.od->OCIDescriptors); + if (count) { + fprintf(stderr, "%d Object Content Information descriptors in OD\n", count); + for (i=0; iOCIDescriptors, i); + switch (desc->tag) { + case GF_ODF_SEGMENT_TAG: + { + GF_Segment *sd = (GF_Segment *) desc; + fprintf(stderr, "Segment Descriptor: Name: %s - start time %g sec - duration %g sec\n", sd->SegmentName, sd->startTime, sd->Duration); + } + break; + case GF_ODF_CC_NAME_TAG: + { + GF_CC_Name *ccn = (GF_CC_Name *)desc; + fprintf(stderr, "Content Creators:\n"); + for (j=0; jContentCreators); j++) { + GF_ContentCreatorInfo *ci = (GF_ContentCreatorInfo *) gf_list_get(ccn->ContentCreators, j); + if (!ci->isUTF8) continue; + fprintf(stderr, "\t%s\n", ci->contentCreatorName); + } + } + break; + + case GF_ODF_SHORT_TEXT_TAG: + { + GF_ShortTextual *std = (GF_ShortTextual *)desc; + fprintf(stderr, "Description:\n\tEvent: %s\n\t%s\n", std->eventName, std->eventText); + } + break; + default: + break; + } + } + fprintf(stderr, "\n"); + } + + switch (odi.status) { + case 0: + fprintf(stderr, "Stopped - "); + break; + case 1: + fprintf(stderr, "Playing - "); + break; + case 2: + fprintf(stderr, "Paused - "); + break; + case 3: + fprintf(stderr, "Not setup yet\n"); + return; + default: + fprintf(stderr, "Setup Failed\n"); + return; + } + if (odi.buffer>=0) fprintf(stderr, "Buffer: %d ms - ", odi.buffer); + else fprintf(stderr, "Not buffering - "); + fprintf(stderr, "Clock drift: %d ms\n", odi.clock_drift); + if (odi.db_unit_count) fprintf(stderr, "%d AU in DB\n", odi.db_unit_count); + if (odi.cb_max_count) fprintf(stderr, "Composition Buffer: %d CU (%d max)\n", odi.cb_unit_count, odi.cb_max_count); + fprintf(stderr, "\n"); + + if (odi.owns_service) { + const char *url; + u32 done, total, bps; + d_enum = 0; + while (gf_term_get_download_info(term, odm, &d_enum, &url, NULL, &done, &total, &bps)) { + if (d_enum==1) fprintf(stderr, "Current Downloads in service:\n"); + if (done && total) { + fprintf(stderr, "%s: %d / %d bytes (%.2f %%) - %.2f kBps\n", url, done, total, (100.0f*done)/total, ((Float)bps)/1024.0f); + } else { + fprintf(stderr, "%s: %.2f kbps\n", url, ((Float)8*bps)/1024.0f); + } + } + if (!d_enum) fprintf(stderr, "No Downloads in service\n"); + fprintf(stderr, "\n"); + } + d_enum = 0; + while (gf_term_get_channel_net_info(term, odm, &d_enum, &id, &com, &e)) { + if (e) continue; + if (!com.bw_down && !com.bw_up) continue; + + fprintf(stderr, "Stream ID %d statistics:\n", id); + if (com.multiplex_port) { + fprintf(stderr, "\tMultiplex Port %d - multiplex ID %d\n", com.multiplex_port, com.port); + } else { + fprintf(stderr, "\tPort %d\n", com.port); + } + fprintf(stderr, "\tPacket Loss Percentage: %.4f\n", com.pck_loss_percentage); + fprintf(stderr, "\tDown Bandwidth: %d bps\n", com.bw_down); + if (com.bw_up) fprintf(stderr, "\tUp Bandwidth: %d bps\n", com.bw_up); + if (com.ctrl_port) { + if (com.multiplex_port) { + fprintf(stderr, "\tControl Multiplex Port: %d - Control Multiplex ID %d\n", com.multiplex_port, com.ctrl_port); + } else { + fprintf(stderr, "\tControl Port: %d\n", com.ctrl_port); + } + fprintf(stderr, "\tDown Bandwidth: %d bps\n", com.ctrl_bw_down); + fprintf(stderr, "\tUp Bandwidth: %d bps\n", com.ctrl_bw_up); + } + fprintf(stderr, "\n"); + } +} + +void PrintODTiming(GF_Terminal *term, GF_ObjectManager *odm, u32 indent) +{ + GF_MediaInfo odi; + u32 ind = indent; + u32 i, count; + if (!odm) return; + + if (gf_term_get_object_info(term, odm, &odi) != GF_OK) return; + if (!odi.od) { + fprintf(stderr, "Service not attached\n"); + return; + } + while (ind) { + fprintf(stderr, " "); + ind--; + } + + if (! odi.generated_scene) { + + fprintf(stderr, "- OD %d: ", odi.od->objectDescriptorID); + switch (odi.status) { + case 1: + fprintf(stderr, "Playing - "); + break; + case 2: + fprintf(stderr, "Paused - "); + break; + default: + fprintf(stderr, "Stopped - "); + break; + } + if (odi.buffer>=0) fprintf(stderr, "Buffer: %d ms - ", odi.buffer); + else fprintf(stderr, "Not buffering - "); + fprintf(stderr, "Clock drift: %d ms", odi.clock_drift); + fprintf(stderr, " - time: "); + PrintTime((u32) (odi.current_time*1000)); + fprintf(stderr, "\n"); + + } else { + fprintf(stderr, "+ Service %s:\n", odi.service_url); + } + + count = gf_term_get_object_count(term, odm); + for (i=0; iobjectDescriptorID); + switch (odi.status) { + case 1: + fprintf(stderr, "Playing"); + break; + case 2: + fprintf(stderr, "Paused"); + break; + default: + fprintf(stderr, "Stopped"); + break; + } + if (odi.buffer>=0) fprintf(stderr, " - Buffer: %d ms", odi.buffer); + if (odi.db_unit_count) fprintf(stderr, " - DB: %d AU", odi.db_unit_count); + if (odi.cb_max_count) fprintf(stderr, " - CB: %d/%d CUs", odi.cb_unit_count, odi.cb_max_count); + + fprintf(stderr, "\n"); + ind = indent; + while (ind) { + fprintf(stderr, " "); + ind--; + } + + fprintf(stderr, " %d decoded frames - %d dropped frames\n", odi.nb_dec_frames, odi.nb_dropped); + + ind = indent; + while (ind) { + fprintf(stderr, " "); + ind--; + } + + avg_dec_time = 0; + if (odi.nb_dec_frames) { + avg_dec_time = (Float) odi.total_dec_time; + avg_dec_time /= odi.nb_dec_frames; + } + fprintf(stderr, " Avg Bitrate %d kbps (%d max) - Avg Decoding Time %.2f us (%d max)\n", + (u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time); + } + + count = gf_term_get_object_count(term, odm); + for (i=0; i scanf("%s", szName)) { + fprintf(stderr, "No section name, aborting.\n"); + return; + } + if (strcmp(szName, "*")) secName = szName; + + fprintf(stderr, "\n\n*** GPAC Configuration ***\n\n"); + + cfg_count = gf_cfg_get_section_count(cfg_file); + for (i=0; i.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/testapps/bmp4demux/bmp4demux.sln b/applications/testapps/bmp4demux/bmp4demux.sln new file mode 100644 index 0000000..e304373 --- /dev/null +++ b/applications/testapps/bmp4demux/bmp4demux.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bmp4demux", "bmp4demux.vcxproj", "{978A2D9F-E44F-4073-8032-333563BCC160}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.ActiveCfg = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.Build.0 = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.ActiveCfg = Release|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/applications/testapps/bmp4demux/bmp4demux.vcxproj b/applications/testapps/bmp4demux/bmp4demux.vcxproj new file mode 100644 index 0000000..f167d44 --- /dev/null +++ b/applications/testapps/bmp4demux/bmp4demux.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {978A2D9F-E44F-4073-8032-333563BCC160} + bmp4demux + + + + Application + v110 + false + MultiByte + + + Application + v100 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + AllRules.ruleset + + + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + AllRules.ruleset + + + + + + .\Debug/bmp4demux.tlb + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + true + Level3 + true + EditAndContinue + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + MachineX86 + + + true + .\Debug/bmp4demux.bsc + + + + + .\Release/bmp4demux.tlb + + + + MaxSpeed + OnlyExplicitInline + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/bmp4demux.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) + .\Release/bmp4demux.pdb + Console + MachineX86 + + + true + .\Release/bmp4demux.bsc + + + + + + \ No newline at end of file diff --git a/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters b/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters new file mode 100644 index 0000000..4a097c1 --- /dev/null +++ b/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters @@ -0,0 +1,137 @@ + + + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + + others + + + others + + + others + + + others + + + others + + + others + + + isoff + + + others + + + + + {c9a8f639-328c-4505-be50-4859357c2c00} + + + {e5ca7285-ca00-49d8-ac81-dff3d494be9a} + + + \ No newline at end of file diff --git a/applications/testapps/bmp4demux/build.sh b/applications/testapps/bmp4demux/build.sh new file mode 100644 index 0000000..d1dd330 --- /dev/null +++ b/applications/testapps/bmp4demux/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_file.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB diff --git a/applications/testapps/bmp4demux/main.c b/applications/testapps/bmp4demux/main.c new file mode 100644 index 0000000..cbe7cac --- /dev/null +++ b/applications/testapps/bmp4demux/main.c @@ -0,0 +1,93 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2013- + * All rights reserved + * + * This file is part of GPAC / sample MP4 demultiplexing application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +int main(int argc, char **argv) +{ + /* The ISO progressive reader */ + GF_ISOFile *movie; + /* Error indicator */ + GF_Err e; + /* Number of bytes required to finish the current ISO Box reading */ + u64 missing_bytes; + /* Return value for the program */ + int ret = 0; + u32 track_id = 1; + u32 track_number; + u32 sample_count; + u32 sample_index; + + /* Usage */ + if (argc < 2) { + fprintf(stdout, "Usage: %s filename [track_id]\n", argv[0]); + return 1; + } + if (argc == 3) { + track_id = atoi(argv[2]); + } + + e = gf_isom_open_progressive(argv[1], 0, 0, &movie, &missing_bytes); + if ((e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) || movie == NULL) { + fprintf(stdout, "Could not open file %s for reading (%s).\n", argv[1], gf_error_to_string(e)); + return 1; + } + + track_number = gf_isom_get_track_by_id(movie, track_id); + if (track_number == 0) { + fprintf(stdout, "Could not find track ID=%u of file %s.\n", track_id, argv[1]); + ret = 1; + goto exit; + } + + sample_count = gf_isom_get_sample_count(movie, track_number); + sample_index = 1; + while (sample_index <= sample_count) { + GF_ISOSample *iso_sample; + u32 sample_description_index; + + iso_sample = gf_isom_get_sample(movie, track_number, sample_index, &sample_description_index); + if (iso_sample) { + fprintf(stdout, "Found sample #%5d/%5d of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\n", sample_index, sample_count, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset); + sample_index++; + + /*release the sample data, once you're done with it*/ + gf_isom_sample_del(&iso_sample); + } else { + e = gf_isom_last_error(movie); + if (e == GF_ISOM_INCOMPLETE_FILE) { + missing_bytes = gf_isom_get_missing_bytes(movie, track_number); + fprintf(stdout, "Missing "LLU" bytes on input file\n", missing_bytes); + gf_sleep(1000); + } + } + } + +exit: + gf_isom_close(movie); + + return ret; +} diff --git a/applications/testapps/broadcaster/Makefile b/applications/testapps/broadcaster/Makefile new file mode 100644 index 0000000..eaf7bd4 --- /dev/null +++ b/applications/testapps/broadcaster/Makefile @@ -0,0 +1,34 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/testapps/broadcaster + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +SOURCES= +APPNAME=broadcaster + + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS=RTP_serv_generator.o RTP_serv_packetizer.o RTP_serv_sender.o broadcaster.o sdp_generator.o debug.o + +LINKFLAGS=-L../../../bin/gcc -lgpac + +all: broadcaster + +broadcaster: $(OBJS) *.h + $(CC) $(LDFLAGS) -o $(APPNAME) $(OBJS) $(LINKFLAG) + +clean: + -rm -f $(OBJS) $(APPNAME) *~ + + diff --git a/applications/testapps/broadcaster/RTP_serv_generator.c b/applications/testapps/broadcaster/RTP_serv_generator.c new file mode 100644 index 0000000..027aa3a --- /dev/null +++ b/applications/testapps/broadcaster/RTP_serv_generator.c @@ -0,0 +1,286 @@ +#include +#include +#include + +#include "RTP_serv_generator.h" +#include "debug.h" + +/* Callback function called when encoding of BT is done */ +GF_Err SampleCallBack(void *calling_object, u16 ESID, char *au, u32 size, u64 ts) +{ + PNC_CallbackData *data = (PNC_CallbackData *)calling_object; + /* call the packetizer to create RTP packets */ + PNC_ProcessData(data, au, size, ts); + return GF_OK; +} + +GF_Err (*MySampleCallBack)(void *, u16, char *data, u32 size, u64 ts) = &SampleCallBack; + +PNC_CallbackData *PNC_Init_SceneGenerator(GF_RTPChannel *p_chan, GF_RTPHeader *p_hdr, char *default_scene, + u32 socketType, u16 socketPort, int debug) +{ + GF_Err e; + PNC_CallbackData *data = gf_malloc(sizeof(PNC_CallbackData)); + int *i; + data->chan = p_chan; + data->hdr = p_hdr; + data->debug = debug; + memset( (void*) (data->buffer), '\0', RECV_BUFFER_SIZE_FOR_COMMANDS); + data->bufferPosition = 0; + /* Loading the initial scene as the encoding context */ + data->codec = gf_seng_init((void*)data, default_scene); + if (!data->codec) { + fprintf(stderr, "Cannot create BIFS Engine from %s\n", default_scene); + gf_free(data); + return NULL; + } + data->server_socket = NULL; + data->socket = NULL; + + if (socketType == GF_SOCK_TYPE_TCP) + { + data->server_socket = gf_sk_new(socketType); + e = gf_sk_bind(data->server_socket, NULL, (u16) socketPort, NULL, 0, 0); + if (e) + fprintf(stderr, "Failed to bind : %s\n", gf_error_to_string(e)); + e |= gf_sk_listen(data->server_socket, 1); + if (e) + fprintf(stderr, "Failed to listen : %s\n", gf_error_to_string(e)); + e |= gf_sk_set_block_mode(data->server_socket, 0); + if (e) + fprintf(stderr, "Failed to set block mode : %s\n", gf_error_to_string(e)); + e |= gf_sk_server_mode(data->server_socket, 0); + if (e) + fprintf(stderr, "Failed to set server mode : %s\n", gf_error_to_string(e)); + } else { + data->socket = gf_sk_new(socketType); + e = gf_sk_bind(data->socket, NULL, (u16) socketPort, NULL, 0, 0); + } + /* + char buffIp[1024]; + u16 port = 0; + u32 socket_type = 0; + e |= gf_sk_get_local_ip(data->socket, buffIp); + e |= gf_sk_get_local_info(data->socket, &port, &socket_type); + dprintf(DEBUG_RTP_serv_generator, "RTS_serv_generator %s:%d %s\n", + buffIp, port, socket_type==GF_SOCK_TYPE_UDP?"UDP":"TCP", e==GF_OK?"OK":"ERROR"); + */ + if (e) { + fprintf(stderr, "Cannot bind socket to port %d (%s)\n", socketPort, gf_error_to_string(e)); + if (data->socket) + gf_sk_del(data->socket); + if (data->server_socket) + gf_sk_del(data->server_socket); + gf_free(data); + return NULL; + } + data->extension = gf_malloc(sizeof(PNC_CallbackExt)); + ((PNC_CallbackExt * )data->extension)->i = 0; + ((PNC_CallbackExt * )data->extension)->lastTS = 0; + i = &((PNC_CallbackExt*)data->extension)->i; + return data; +} + +void PNC_SendInitScene(PNC_CallbackData * data) +{ + data->RAP = 1; + data->SAUN_inc = 1; + gf_seng_encode_context(data->codec, MySampleCallBack); +} + +void PNC_Close_SceneGenerator(PNC_CallbackData * data) +{ + if (data->extension) gf_free(data->extension); + gf_seng_terminate(data->codec); + gf_rtp_del(data->chan); + PNC_ClosePacketizer(data); + gf_free(data); +} + + +/** + * Finds the command directive if any + */ +static int findCommand(const char * buffer, int searchFrom) +{ + char * sstr; + assert( buffer ); + assert( searchFrom >= 0); + /** We may have received #RTP_STREAM_ directive before the last update */ + if (searchFrom < 30) { + searchFrom = 0; + } else { + searchFrom-= 30; + } + sstr = strstr(&(buffer[searchFrom]), "#_RTP_STREAM_"); + if (sstr) { + return (sstr - buffer); + } + return -1; +} + +static GF_Err processSend(PNC_CallbackData * data, char * bsBuffer) +{ + GF_Err error; + assert( data ); + assert( bsBuffer ); + assert( data->codec ); + dprintf(DEBUG_RTP_serv_generator, "RTP STREAM SEND\n"); + gf_mx_p(data->carrousel_mutex); + error = gf_seng_encode_from_string(data->codec, 0, 0, bsBuffer, MySampleCallBack); + gf_mx_v(data->carrousel_mutex); + gf_free( bsBuffer ); + return error; +} + +static GF_Err processRapReset(PNC_CallbackData * data, char * bsBuffer) +{ + GF_Err error; + dprintf(DEBUG_RTP_serv_generator, "RTP STREAM RAP RESET\n"); + gf_mx_p(data->carrousel_mutex); + data->RAP = 1; + data->RAPsent++; + data->SAUN_inc = 1; + error = gf_seng_aggregate_context(data->codec, 0); + if (error == GF_OK) + error = gf_seng_encode_context(data->codec, MySampleCallBack); + gf_mx_v(data->carrousel_mutex); + gf_free( bsBuffer ); + return error; +} + +static GF_Err processRap(PNC_CallbackData * data, char * bsBuffer) +{ + GF_Err error; + dprintf(DEBUG_RTP_serv_generator, "RTP STREAM RAP\n"); + gf_mx_p(data->carrousel_mutex); + data->SAUN_inc = 1; + data->RAP = 1; + data->RAPsent++; + error = gf_seng_aggregate_context(data->codec, 0); + if (GF_OK == error) + error = gf_seng_encode_context(data->codec, MySampleCallBack); + gf_mx_v(data->carrousel_mutex); + gf_free( bsBuffer ); + return error; +} + +static GF_Err processSendCritical(PNC_CallbackData * data, char * bsBuffer) +{ + GF_Err error; + dprintf(DEBUG_RTP_serv_generator, "RTP STREAM SEND CRITICAL\n"); + gf_mx_p(data->carrousel_mutex); + data->SAUN_inc = 1; + error = gf_seng_encode_from_string(data->codec, 0, 0, bsBuffer, MySampleCallBack); + gf_mx_v(data->carrousel_mutex); + gf_free( bsBuffer ); + return error; +} + +/** + * Allocates a new buffer for output and copy everything in it; + * then copy off data from newStart to upToPosition. + */ +static char * eat_buffer_to_bs(char * data, int newStart, int upToPosition, int dataFullSize) +{ + char * newBuffer; + + /* Sanity checks */ + assert(data); + assert(newStart >= 0); + assert(upToPosition >= 0); + assert(dataFullSize > 0); + assert(newStart < upToPosition); + data[upToPosition] = '\0'; + newBuffer = NULL; + + /*new length + '\0'*/ + assert(dataFullSize >= upToPosition-newStart+2); + newBuffer = (char*)gf_malloc(dataFullSize); + memcpy(newBuffer, data, dataFullSize); + memcpy(data, newBuffer+newStart, upToPosition-newStart+1); + data[upToPosition-newStart+1]='\0'; + dprintf(DEBUG_RTP_serv_generator, "Generated : '%s'\n", newBuffer); + return newBuffer; +} + +GF_Err PNC_processBIFSGenerator(PNC_CallbackData * data) +{ + const int tmpBufferSize = 2048; + char *tmpBuffer = (char*)alloca(tmpBufferSize); + int byteRead=0; + + char *bsBuffer; + int retour=0; + GF_Err e; + + if (data->server_socket) + { + data->socket = NULL; + e = gf_sk_accept(data->server_socket, &(data->socket)); + if (e) { + return GF_OK; + } else { + dprintf(DEBUG_RTP_serv_generator, "New TCP client connected !\n"); + } + } + + do + { + if (data->socket == NULL) + return GF_OK; + e = gf_sk_receive(data->socket, tmpBuffer, tmpBufferSize, 0, & byteRead); + switch (e) { + case GF_IP_NETWORK_EMPTY: + e = GF_OK; + break; + case GF_OK: + if (byteRead > 0) { + dprintf(DEBUG_RTP_serv_generator, "Received %d bytes\n", byteRead); + /* We copy data in buffer */ + memcpy( &(data->buffer[data->bufferPosition]), tmpBuffer, byteRead ); + data->buffer[data->bufferPosition + byteRead] = '\0'; + retour = findCommand( data->buffer, data->bufferPosition); + data->bufferPosition += byteRead; + if (retour >= 0) { + /** OK, it means we found a command ! */ + if (strncmp(&(data->buffer[retour+13]), + "SEND_CRITICAL", 13)==0) { + bsBuffer = eat_buffer_to_bs( data->buffer, retour, retour + 26, RECV_BUFFER_SIZE_FOR_COMMANDS); + data->bufferPosition = 0; + return processSendCritical(data, bsBuffer); + } + if (strncmp(&(data->buffer[retour+13]), "SEND", 4)==0) { + bsBuffer = eat_buffer_to_bs( data->buffer, retour, retour + 17, RECV_BUFFER_SIZE_FOR_COMMANDS); + data->bufferPosition = 0; + return processSend(data, bsBuffer); + } + if (strncmp(&(data->buffer[retour+13]), "RAP", 3)==0) { + bsBuffer = eat_buffer_to_bs( data->buffer, retour, retour + 16, RECV_BUFFER_SIZE_FOR_COMMANDS); + data->bufferPosition = 0; + return processRap(data, bsBuffer); + } + if (strncmp(&(data->buffer[retour+13]), "RAP_RESET", 9)==0) { + bsBuffer = eat_buffer_to_bs( data->buffer, retour, retour + 22, RECV_BUFFER_SIZE_FOR_COMMANDS); + data->bufferPosition = 0; + return processRapReset(data, bsBuffer); + } + /** If we are here, it means probably we did not received fully the command */ + break; + } + } + /* No bytes were received */ + break; + default: + fprintf(stderr, "Socket error while receiving BIFS data %s\n", gf_error_to_string(e)); + if (data->socket != NULL) { + gf_sk_del(data->socket); + data->socket = NULL; + } + return e; + } + + } while (e == GF_OK); + + return GF_OK; +} diff --git a/applications/testapps/broadcaster/RTP_serv_generator.h b/applications/testapps/broadcaster/RTP_serv_generator.h new file mode 100644 index 0000000..7a99a79 --- /dev/null +++ b/applications/testapps/broadcaster/RTP_serv_generator.h @@ -0,0 +1,66 @@ +#ifndef _RTP_SERV_GENERATOR_H_ +#define _RTP_SERV_GENERATOR_H_ +#include + +#include +#include // sockets +#include +#include +#include + +#include +#define RECV_BUFFER_SIZE_FOR_COMMANDS 262144 + + +/*callback type (allows reentrance)*/ +typedef struct tmp_PNC_CallbackData { + GF_RTPChannel *chan; + GF_RTPHeader *hdr; + char * formatedPacket; + int formatedPacketLength; + GP_RTPPacketizer *rtpBuilder; + GF_SceneEngine *codec; + + /* socket on which updates are received */ + GF_Socket *socket; + GF_Socket *server_socket; + /* socket on which bitrate feedback is sent */ + GF_Socket *feedback_socket; + + void *extension; + + /* indication that the Access Unit is a RAP */ + int RAP; + /* RAP counter */ + int RAPsent; + /* indication that the Access Unit Sequence Number should be increased */ + int SAUN_inc; + + GF_Mutex *carrousel_mutex; + char buffer[RECV_BUFFER_SIZE_FOR_COMMANDS]; + int bufferPosition; + int debug; +} PNC_CallbackData; + + + +#define RTP_SERV_GENERATOR_DEBUG 0x4 + +typedef struct tmp_PNC_CallbackExt { + int i; + int lastTS; +} PNC_CallbackExt; + + +/*exports*/ +extern GF_Err PNC_RAP(PNC_CallbackData *data); +extern PNC_CallbackData* PNC_Init_SceneGenerator(GF_RTPChannel *p_chan, GF_RTPHeader *p_hdr, char *default_scene, + u32 socketType, u16 socketPort, int debug); +extern GF_Err PNC_processBIFSGenerator(PNC_CallbackData*); +extern void PNC_Close_SceneGenerator(PNC_CallbackData*); + +extern void PNC_SendInitScene(PNC_CallbackData * data); + +#include "RTP_serv_packetizer.h" + +#endif \ No newline at end of file diff --git a/applications/testapps/broadcaster/RTP_serv_packetizer.c b/applications/testapps/broadcaster/RTP_serv_packetizer.c new file mode 100644 index 0000000..6021644 --- /dev/null +++ b/applications/testapps/broadcaster/RTP_serv_packetizer.c @@ -0,0 +1,92 @@ +#include "RTP_serv_packetizer.h" +#include "RTP_serv_sender.h" +#include + +#include +#include +#include + +#define MAX_PACKET_SIZE 2000 + +#include "debug.h" + + +void OnNewPacket(void *cbk, GF_RTPHeader *header) +{ + ((PNC_CallbackData *)cbk)->formatedPacketLength = 0; +} + +void OnPacketDone(void *cbk, GF_RTPHeader *header) +{ + PNC_CallbackData *data = (PNC_CallbackData *)cbk; + dprintf(DEBUG_RTP_serv_packetizer, "RTP Packet done\n"); + PNC_SendRTP(data, ((PNC_CallbackData *)cbk)->formatedPacket, ((PNC_CallbackData *)cbk)->formatedPacketLength); + ((PNC_CallbackData *)cbk)->formatedPacketLength = 0; +} + +void OnData(void *cbk, char *data, u32 data_size, Bool is_head) +{ + memcpy(((PNC_CallbackData *)cbk)->formatedPacket+((PNC_CallbackData *)cbk)->formatedPacketLength, data, data_size); + ((PNC_CallbackData *)cbk)->formatedPacketLength += data_size; +} + +void PNC_InitPacketiser(PNC_CallbackData * data, char *sdp_fmt, unsigned short mtu_size) +{ + GP_RTPPacketizer *p; + GF_SLConfig sl; + memset(&sl, 0, sizeof(sl)); + sl.useTimestampsFlag = 1; + sl.useRandomAccessPointFlag = 1; + sl.timestampResolution = 1000; + sl.AUSeqNumLength = 16; + + p = gf_rtp_builder_new(GF_RTP_PAYT_MPEG4, + &sl, + GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_AU_IDX, + data, + OnNewPacket, + OnPacketDone, + NULL, + OnData); + if (!p) { + fprintf(stderr, "Cannot create RTP builder \n"); + return; + } + + /* Mtu size - 20 = payload max size */ + mtu_size-=20; + gf_rtp_builder_init(p, 96, mtu_size, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, NULL); + gf_rtp_builder_format_sdp(p, "mpeg4-generic", sdp_fmt, NULL, 0); + p->rtp_header.Version=2; + p->rtp_header.SSRC=rand(); + data->hdr=& p->rtp_header; + data->rtpBuilder=p; + data->formatedPacket = gf_malloc(MAX_PACKET_SIZE); + data->formatedPacketLength = 0; +} + +void PNC_ClosePacketizer(PNC_CallbackData *data) +{ + gf_free(data->formatedPacket); + gf_rtp_builder_del(data->rtpBuilder); +} + +GF_Err PNC_ProcessData(PNC_CallbackData * data, char *au, u32 size, u64 ts) +{ + assert( data ); + assert( au ); + /* We need to set a TS different every time */ + data->hdr->TimeStamp = (u32) gf_sys_clock(); + data->rtpBuilder->sl_header.compositionTimeStamp = (u32) gf_sys_clock(); + data->rtpBuilder->sl_header.randomAccessPointFlag = data->RAP; + if (data->SAUN_inc) data->rtpBuilder->sl_header.AU_sequenceNumber++; + + /* reset input data config */ + data->RAP=0; + data->SAUN_inc=0; + + data->rtpBuilder->sl_header.paddingBits = 0; + gf_rtp_builder_process(data->rtpBuilder, au, size, 1, size, 0, 0); + + return GF_OK; +} diff --git a/applications/testapps/broadcaster/RTP_serv_packetizer.h b/applications/testapps/broadcaster/RTP_serv_packetizer.h new file mode 100644 index 0000000..9cec6ee --- /dev/null +++ b/applications/testapps/broadcaster/RTP_serv_packetizer.h @@ -0,0 +1,13 @@ +#ifndef __RTP_SERV_PACKETISER +#define __RTP_SERV_PACKETISER + +#include +#include "gpac/scene_engine.h" // For M4Sample +#include "RTP_serv_generator.h" + +/*exports*/ +void PNC_InitPacketiser(PNC_CallbackData *data, char *sdp_fmt, unsigned short mtu_size); +GF_Err PNC_ProcessData(PNC_CallbackData *data, char *au, u32 size, u64 ts); +void PNC_ClosePacketizer(PNC_CallbackData *data); + +#endif diff --git a/applications/testapps/broadcaster/RTP_serv_sender.c b/applications/testapps/broadcaster/RTP_serv_sender.c new file mode 100644 index 0000000..7dd8ddf --- /dev/null +++ b/applications/testapps/broadcaster/RTP_serv_sender.c @@ -0,0 +1,83 @@ +#include "RTP_serv_sender.h" +#include +#include +#include "debug.h" + + +GF_Err PNC_InitRTP(GF_RTPChannel **chan, char *dest, int port, unsigned short mtu_size) +{ + GF_Err res; + GF_RTSPTransport tr; + + *chan = gf_rtp_new(); + res = gf_rtp_set_ports(*chan, 0); + if (res) { + fprintf(stderr, "Cannot set RTP ports: %s\n", gf_error_to_string(res)); + gf_rtp_del(*chan); + return res; + } + + tr.destination = dest; + tr.IsUnicast = gf_sk_is_multicast_address(dest) ? 0 : 1; + tr.Profile="RTP/AVP";//RTSP_PROFILE_RTP_AVP; + tr.IsRecord = 0; + tr.Append = 0; + tr.source = "0.0.0.0"; + tr.SSRC=rand(); + + tr.port_first = port; + tr.port_last = port+1; + if (tr.IsUnicast) { + tr.client_port_first = port; + tr.client_port_last = port+1; + } else { + tr.source = dest; + tr.client_port_first = 0; + tr.client_port_last = 0; + } + + res = gf_rtp_setup_transport(*chan, &tr, dest); + if (res) { + fprintf(stderr, "Cannot setup RTP transport %s\n", gf_error_to_string(res)); + gf_rtp_del(*chan); + return res; + } + + res = gf_rtp_initialize(*chan, 0, 1, mtu_size, 0, 0, NULL); + if (res) { + fprintf(stderr, "Cannot initialize RTP transport %s\n", gf_error_to_string(res)); + gf_rtp_del(*chan); + return res; + } + return GF_OK; +} + + +GF_Err PNC_SendRTP(PNC_CallbackData *data, char *payload, int payloadSize) +{ + GF_Err e; + unsigned char feedback_buffer[250]; + + if (!data->hdr->TimeStamp) + data->hdr->TimeStamp = ((PNC_CallbackExt * )data->extension)->lastTS; + + ((PNC_CallbackExt * )data->extension)->lastTS = data->hdr->TimeStamp; + + e = gf_rtp_send_packet(data->chan, data->hdr, payload, payloadSize, 0); + dprintf(DEBUG_RTP_serv_sender, "SendPacket : %d, TimeStamp RTP = %d, sz= %d\n", + e, data->hdr->TimeStamp, payloadSize); + + // sending feedback bytes + memset(feedback_buffer, 0, sizeof(feedback_buffer)); + sprintf((char *) feedback_buffer, "DataSent=%d\nRAPsent=%d\n", payloadSize, data->RAPsent); + e = gf_sk_send(data->feedback_socket, feedback_buffer, strlen((char *) feedback_buffer)); + dprintf(DEBUG_RTP_serv_packetizer, "Sent feedback data %d byte, return %d\n", payloadSize, e); + + return GF_OK; +} + +GF_Err PNC_CloseRTP(GF_RTPChannel *chan) +{ + gf_rtp_del(chan); + return GF_OK; +} diff --git a/applications/testapps/broadcaster/RTP_serv_sender.h b/applications/testapps/broadcaster/RTP_serv_sender.h new file mode 100644 index 0000000..99562f7 --- /dev/null +++ b/applications/testapps/broadcaster/RTP_serv_sender.h @@ -0,0 +1,14 @@ +#ifndef __RTP_SERV_SENDER +#define __RTP_SERV_SENDER + +#include /// For GF_Err ... +#include "RTP_serv_generator.h" + +extern void test_RTP_serv_send(); + +extern GF_Err PNC_InitRTP(GF_RTPChannel **chan, char *dest, int port, unsigned short mtu_size); +extern GF_Err PNC_SendRTP(PNC_CallbackData *data, char *payload, int payloadSize); +extern GF_Err PNC_CloseRTP(GF_RTPChannel *chan); + + +#endif diff --git a/applications/testapps/broadcaster/broadcaster.c b/applications/testapps/broadcaster/broadcaster.c new file mode 100644 index 0000000..85398a4 --- /dev/null +++ b/applications/testapps/broadcaster/broadcaster.c @@ -0,0 +1,546 @@ +#include "broadcaster.h" +#include "debug.h" + +static void printIncompatibleOptions() +{ + fprintf(stderr, "Options config file and tcp port are incompatible !\n"); +} + +extern GF_Err SampleCallBack(void *, u16, char *data, u32 size, u64 ts); + +/** + * Returns a port from a char value, will return 0 if port is not valid + */ +static unsigned short port_from_string(const char * port_to_parse) +{ + unsigned long int v; + char * endptr = '\0'; + const char * value = port_to_parse; + if (value == NULL || value[0] == '\0') { + fprintf(stderr, "Value for port cannot be empty"); + return 0; + } + v = strtoul(value, &endptr, 10); + if (*endptr != '\0' || v < 1 || v > 65535) { + fprintf(stderr, "Value %s is not a valid port, port must be between 1 and 65535 !\n", value); + return 0; + } + return (unsigned short) v; +} + +static int command_line_parsing(int argc, const char** argv, unsigned short * tcp_port, + char *config_file, int *config_flag, unsigned short * mtu_size, + int * debug, u32 * socketType_for_updates) +{ + int counter = 1; + if (argc < 2 || argc%2 != 1) { + fprintf(stderr, "Incorrect number of arguments, must be multiple of 2 (Please specify at least -f or -p arguments) !\n"); + return -5; + } + + for(counter = 1; counter < (argc - 1); counter+=2) + { + const char * a = argv[counter]; + if (!strcmp("-p", a) || !strcmp("--port", a)) + { + if (*config_flag) + { + printIncompatibleOptions(); + return -2; + } + (*tcp_port) = port_from_string( argv[counter + 1] ); + if (!(*tcp_port)) return -3; + } + else if (!strcmp("-f", a) || !strcmp("--file", a)) + { + if (*tcp_port) { + printIncompatibleOptions(); + return -2; + } + strcpy(config_file, argv[counter+1]); + (*config_flag) = 1; + } + else if (!strcmp("-m", a) || !strcmp("--mtu", a)) + { + *mtu_size = atoi(argv[counter+1]); + if (!(mtu_size)) return -3; + } + else if (!strcmp("-d", a) || !strcmp("--debug", a)) + { + *debug = atoi(argv[counter+1]); + } + else if (!strcmp("-s", a) || !strcmp("--socket-type-for-updates", a)) + { + *socketType_for_updates = 0 == stricmp("TCP", argv[counter+1]); + } + else + { + fprintf(stderr, "Unknown parameter %s.", a); + return -2; + } + } + + if (!(*config_flag) && !(*tcp_port)) { + fprintf(stderr, "No config file or port specified !\n"); + return -6; + } + + return 0; +} + +void print_usage(void) +{ + fprintf(stdout, "BIFS Scene encoder and streamer (c) Telecom ParisTech 2009\n"); + fprintf(stdout, "USAGE: broadcaster [-p tcp_port] [-s TCP|UDP] [-f config_file_name] [-m mtu_size] -d [debug]\n"); + fprintf(stdout, "\tIndicate the location of the configuration file either with a TCP port number or a file name\n"); + fprintf(stdout, "\tmtu_size : the MTU size (default = 1492)\n"); + fprintf(stdout, "\t-s or --socket-type-for-updates : connection type for updates (UDP by default)\n"); + fprintf(stdout, "\tdebug: OR debug mask (broadcaster = 1, scene_generator=2, sdp_generator=4, ALL=31)\n"); +} + +u32 RAP_send(void *par) +{ + RAP_Input *input = par; + PNC_CallbackData *data = input->data; + u32 *timer; + + input->status = 1; + while (input->status==1) { + gf_mx_p(input->carrousel_mutex); + + timer = input->RAPtimer; + data->RAPsent++; + dprintf(DEBUG_broadcaster, "Sending RAP, will sleep for %d seconds\n", *timer); + data->RAP = 1; + gf_seng_aggregate_context(data->codec, 0); + gf_seng_encode_context(data->codec, SampleCallBack); + + gf_mx_v(input->carrousel_mutex); + gf_sleep((*timer)*1000); + } + input->status = 2; + return GF_OK; +} + +GF_Err parse_config(GF_Config *gf_config_file, CONF_Data *conf, int debug) +{ + conf->scene_init_file = gf_cfg_get_key(gf_config_file, MAIN_SECTION, SCENE_INIT); + if (!conf->scene_init_file) { + fprintf(stderr, "Cannot find initial scene from configuration file\n"); + return GF_IO_ERR; + } else { + dprintf(DEBUG_broadcaster, "Using initial scene: %s\n", conf->scene_init_file); + } + + conf->rap_timer = gf_cfg_get_key(gf_config_file, MAIN_SECTION, RAP_TIMER); + if (!conf->rap_timer) conf->rap_timer = "2"; + dprintf(DEBUG_broadcaster, "Using a RAP period of %s seconds\n", conf->rap_timer); + + conf->config_input_port = gf_cfg_get_key(gf_config_file, MAIN_SECTION, PORT_CONFIG); + if (!conf->config_input_port) conf->config_input_port = "5000"; + dprintf(DEBUG_broadcaster, "Using Configuration Port: %s\n", conf->config_input_port); + + conf->modif_input_port = gf_cfg_get_key(gf_config_file, MAIN_SECTION, PORT_MODIF); + if (!conf->modif_input_port) + conf->modif_input_port = "8000"; + dprintf(DEBUG_broadcaster, "Using Update Port: %s\n", conf->modif_input_port); + + conf->dest_ip = gf_cfg_get_key(gf_config_file, DEST_SECTION, DEST_ADDRESS); + if (!conf->dest_ip) + conf->dest_ip = "127.0.0.1"; + conf->dest_port = gf_cfg_get_key(gf_config_file, DEST_SECTION, PORT_OUTPUT); + if (!conf->dest_port) + conf->dest_port = "7000"; + dprintf(DEBUG_broadcaster, "Destination: %s:%s\n", conf->dest_ip, conf->dest_port); + + conf->feedback_ip = gf_cfg_get_key(gf_config_file, FEEDBACK_SECTION, IP_FEEDBACK); + if (!conf->feedback_ip) conf->feedback_ip = "127.0.0.1"; + conf->feedback_port = gf_cfg_get_key(gf_config_file, FEEDBACK_SECTION, PORT_FEEDBACK); + if (!conf->feedback_port) conf->feedback_port = "5757"; + dprintf(DEBUG_broadcaster, "Feedback host: %s:%s\n", conf->feedback_ip, conf->feedback_port); + return GF_OK; +} + +u32 tcp_server(void *par) +{ + TCP_Input *input = par; + u32 *timer = input->RAPtimer; + char buffer[MAX_BUF]; + unsigned char temp[MAX_BUF]; + FILE *fp; + u32 byte_read; + int ret; + GF_Config *gf_config_file; + GF_Socket *TCP_socket; + GF_Socket *conn_socket; + GF_Err e; + + int debug = input->debug; + input->status = 1; + + TCP_socket = gf_sk_new(GF_SOCK_TYPE_TCP); + e = gf_sk_bind(TCP_socket, NULL, input->port, NULL, 0, 0); + e = gf_sk_listen(TCP_socket, 1); + e = gf_sk_set_block_mode(TCP_socket, 1); + e = gf_sk_server_mode(TCP_socket, 0); + + while(input->status == 1) + { + memset(buffer, 0, sizeof(buffer)); + e = gf_sk_accept(TCP_socket, &conn_socket); + if (e == GF_OK) { + memset(buffer, 0, sizeof(buffer)); + e = gf_sk_receive(conn_socket, buffer, MAX_BUF, 0, &byte_read); + } + + switch (e) { + case GF_IP_NETWORK_EMPTY: + gf_sleep(33); + continue; + case GF_OK: + break; + default: + fprintf(stderr, "Error with TCP socket : %s\n", gf_error_to_string(e)); + exit(1); + break; + } + + if((*(input->config_flag)) == 0) + { + u32 num_retry; + fp = gf_fopen("temp.cfg", "w+"); + if (!fp) { + fprintf(stderr, "Error opening temp file for the configuration\n"); + exit(1); + } + ret = gf_fwrite(buffer, 1, byte_read, fp); + gf_fclose(fp); + + /* parsing config info */ + gf_config_file = gf_cfg_new(".", "temp.cfg"); + if (!gf_config_file) { + fprintf(stderr, "Error opening the config file %s\n", gf_error_to_string(e)); + exit(-1); + } + parse_config(gf_config_file, input->config, debug); + + /* Acknowledging the configuration */ + gf_sk_send(conn_socket, "OK\n", 3); + + memset(temp, 0, sizeof(temp)); + fp = gf_fopen(input->config->scene_init_file, "w+"); + if (!fp) { + fprintf(stderr, "Error opening temp file for reception of the initial scene\n"); + exit(1); + } + num_retry=10; + + while (1) + { + GF_Err e = gf_sk_receive(conn_socket, temp, sizeof(temp), 0, &byte_read); + + if (e == GF_OK) { + gf_fwrite(temp, 1, byte_read, fp); + } else if (e==GF_IP_NETWORK_EMPTY) { + num_retry--; + if (!num_retry) + break; + gf_sleep(1); + } else { + fprintf(stderr, "Error receiving initial scene: %s\n", gf_error_to_string(e)); + break; + } + } + gf_fclose(fp); + *(input->config_flag) = 1; + } + /* we only wait now for the config updates */ + if ( (*(input->config_flag)) == 1) { + ret = sscanf(buffer, "DelaiMax=%d\n", timer); + fprintf(stdout, "RAP timer changed, now : %d\n", *timer); + } + gf_sk_del(conn_socket); + } + + input->status = 2; + return GF_OK; +} + +u8 get_a_char(); +Bool has_input(); + +int main (const int argc, const char** argv) +{ + GF_Err e; + Bool run; + + /* location of the configuration file: 0 wait for config on a socket, 1 use the given file */ + u32 config_flag; + char config_file_name[MAX_BUF]; + + int dest_port; + unsigned short tcp_port = 0; + /* Should be fine on WIFI network */ + unsigned short mtu_size = 1492; + int debug = 0; + TCP_Input *tcp_conf = NULL; + GF_Thread *tcp_thread; + GF_Err th_err_tcp; + + GF_Err th_err_rap; + RAP_Input *rap_conf; + GF_Thread *rap_thread; + + CONF_Data *conf; + GF_Config *gf_config_file; + GF_Err res; + + GF_Socket *UDP_feedback_socket; + u32 socketType_for_updates; + + PNC_CallbackData * data; + GF_RTPChannel * chan; + GF_RTPHeader hdr; + u32 timer = -1; + + GF_Mutex *carrousel_mutex; + char sdp_fmt[5000]; + tcp_thread = NULL; + + /* init gpac lib */ + gf_sys_init(); + + GF_SAFEALLOC(conf, CONF_Data); + + tcp_port = config_flag = 0; + socketType_for_updates = GF_SOCK_TYPE_UDP; + if (command_line_parsing(argc, argv, &tcp_port, config_file_name, (int *) &config_flag, &mtu_size, &debug, &socketType_for_updates)) { + print_usage(); + return -1; + } + setDebugMode( debug ); + gf_config_file = NULL; + if (config_flag == 1) + { + char *cfg_path; + char *cfg_fname; + char *tmp; + + cfg_fname = config_file_name; + cfg_path = config_file_name; + tmp = strrchr(cfg_fname, GF_PATH_SEPARATOR); + if (tmp) { + cfg_fname = tmp+1; + tmp[0] = 0; + } else { + cfg_path = "."; + } + gf_config_file = gf_cfg_new(cfg_path, cfg_fname); + if (!gf_config_file) { + fprintf(stderr, "Cannot open config file %s\n", config_file_name); + return -1; + } else { + dprintf(DEBUG_broadcaster, "Using config file %s.\n", config_file_name); + } + if (parse_config(gf_config_file, conf, debug)) return -1; + tcp_port = atoi(conf->config_input_port); + } + else + { + GF_SAFEALLOC(tcp_conf, TCP_Input); + tcp_conf->config_flag = &config_flag; + tcp_conf->RAPtimer = &timer; + tcp_conf->port = tcp_port; + tcp_conf->config = conf; + tcp_thread = gf_th_new("TCPInterface"); + + /* Starting the thread which will write the received config in a temporary file */ + th_err_tcp = gf_th_run(tcp_thread, tcp_server, tcp_conf); + + fprintf(stdout, "Waiting for configuration on port %d...\n", tcp_conf->port); + + while(config_flag == 0) { + gf_sleep(1000); + } + fprintf(stdout, "Configuration File received. Starting Streaming ...\n"); + } + + timer = atoi(conf->rap_timer); + dest_port = atoi(conf->dest_port); + res = PNC_InitRTP(&chan, (char *)conf->dest_ip, dest_port, mtu_size); + if (res != 0) { + fprintf(stderr, "Cannot initialize RTP output (error: %d)\n", res); + exit(1); + } + + carrousel_mutex = gf_mx_new("Carrousel"); + data = PNC_Init_SceneGenerator(chan, &hdr, (char *) conf->scene_init_file, + socketType_for_updates, (u16) atoi(conf->modif_input_port), debug); + if (!data) { + fprintf(stderr, "Cannot initialize Scene Generator\n"); + exit(1); + } + data->carrousel_mutex = carrousel_mutex; + data->RAPsent = 1; + + UDP_feedback_socket = gf_sk_new(GF_SOCK_TYPE_UDP); + e = gf_sk_bind(UDP_feedback_socket, NULL, (u16)atoi(conf->feedback_port), (char*)conf->feedback_ip, (u16)atoi(conf->feedback_port), 0); + if (e) { + fprintf(stderr, "Cannot bind socket for bitrate feedback information (%s)\n", gf_error_to_string(e)); + } else { + e = gf_sk_set_block_mode(UDP_feedback_socket, 1); + if (e) { + fprintf(stderr, "Cannot set feedback socket block mode (%s)\n", gf_error_to_string(e)); + } + } + data->feedback_socket = UDP_feedback_socket; + + PNC_InitPacketiser(data, sdp_fmt, mtu_size); + PNC_SendInitScene(data); + + GF_SAFEALLOC(rap_conf, RAP_Input); + rap_conf->RAPtimer = &timer; + rap_conf->carrousel_mutex = carrousel_mutex; + rap_conf->data = data; + rap_thread = gf_th_new("RAPGenerator"); + th_err_rap = gf_th_run(rap_thread, RAP_send, rap_conf); + + sdp_generator(data, (char *)conf->dest_ip, sdp_fmt); + + run = 1; + while (run) + { + GF_Err e = PNC_processBIFSGenerator(data); + if (e) { + fprintf(stderr, "Cannot Process BIFS data (%s)\n", gf_error_to_string(e)); + break; + } + + if (has_input()) { + char c = get_a_char(); + switch (c) { + case 'q': + run = 0; + break; + } + } + gf_sleep(10); + } + + /* waiting for termination of the RAP thread */ + rap_conf->status = 0; + while (rap_conf->status != 2) + gf_sleep(0); + gf_free(rap_conf); + gf_th_del(rap_thread); + + /* waiting for termination of the TCP listening thread */ + if (tcp_conf) { + tcp_conf->status = 0; + while (tcp_conf->status != 2) + gf_sleep(0); + gf_free(tcp_conf); + gf_th_del(tcp_thread); + } + + PNC_Close_SceneGenerator(data); + + gf_free(conf); + + if (gf_config_file) + gf_cfg_del(gf_config_file); + + gf_mx_del(carrousel_mutex); + gf_sys_close(); + return 0; +} + +#ifdef WIN32 +#include +#include +Bool has_input() +{ + return kbhit(); +} +u8 get_a_char() +{ + return getchar(); +} +void set_echo_off(Bool echo_off) +{ + DWORD flags; + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + GetConsoleMode(hStdin, &flags); + if (echo_off) flags &= ~ENABLE_ECHO_INPUT; + else flags |= ENABLE_ECHO_INPUT; + SetConsoleMode(hStdin, flags); +} +#else +/*linux kbhit/getchar- borrowed on debian mailing lists, (author Mike Brownlow)*/ +#include + +static struct termios t_orig, t_new; +static s32 ch_peek = -1; + +void init_keyboard() +{ + tcgetattr(0, &t_orig); + t_new = t_orig; + t_new.c_lflag &= ~ICANON; + t_new.c_lflag &= ~ECHO; + t_new.c_lflag &= ~ISIG; + t_new.c_cc[VMIN] = 1; + t_new.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &t_new); +} +void close_keyboard(Bool new_line) +{ + tcsetattr(0,TCSANOW, &t_orig); + if (new_line) fprintf(stdout, "\n"); +} + +void set_echo_off(Bool echo_off) +{ + init_keyboard(); + if (echo_off) t_orig.c_lflag &= ~ECHO; + else t_orig.c_lflag |= ECHO; + close_keyboard(0); +} + +Bool has_input() +{ + u8 ch; + s32 nread; + + init_keyboard(); + if (ch_peek != -1) return 1; + t_new.c_cc[VMIN]=0; + tcsetattr(0, TCSANOW, &t_new); + nread = read(0, &ch, 1); + t_new.c_cc[VMIN]=1; + tcsetattr(0, TCSANOW, &t_new); + if(nread == 1) { + ch_peek = ch; + return 1; + } + close_keyboard(0); + return 0; +} + +u8 get_a_char() +{ + u8 ch; + if (ch_peek != -1) { + ch = ch_peek; + ch_peek = -1; + close_keyboard(1); + return ch; + } + int v = read(0,&ch,1); + close_keyboard(1); + if (v == 0) + return 0; + return ch; +} + +#endif diff --git a/applications/testapps/broadcaster/broadcaster.dsp b/applications/testapps/broadcaster/broadcaster.dsp new file mode 100644 index 0000000..2edf9c5 --- /dev/null +++ b/applications/testapps/broadcaster/broadcaster.dsp @@ -0,0 +1,146 @@ +# Microsoft Developer Studio Project File - Name="broadcaster" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=broadcaster - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "broadcaster.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "broadcaster.mak" CFG="broadcaster - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "broadcaster - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "broadcaster - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "broadcaster - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "broadcaster - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 zlib.lib winmm.lib ws2_32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/broadcaster.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "broadcaster - Win32 Release" +# Name "broadcaster - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\broadcaster.c +# End Source File +# Begin Source File + +SOURCE=.\debug.c +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_generator.c +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_packetizer.c +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_sender.c +# End Source File +# Begin Source File + +SOURCE=.\sdp_generator.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\broadcaster.h +# End Source File +# Begin Source File + +SOURCE=.\debug.h +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_generator.h +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_packetizer.h +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_sender.h +# End Source File +# Begin Source File + +SOURCE=.\sdp_generator.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/broadcaster/broadcaster.h b/applications/testapps/broadcaster/broadcaster.h new file mode 100644 index 0000000..fbcb0d7 --- /dev/null +++ b/applications/testapps/broadcaster/broadcaster.h @@ -0,0 +1,85 @@ +/* includes default */ +#include +#include +#include + +/* includes for gpac library */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* includes for BIFS carousel */ +/* RTP sends */ +#include "RTP_serv_sender.h" +/* packetization */ +#include "RTP_serv_packetizer.h" +/* applicative module */ +#include "RTP_serv_generator.h" + +/* for SDP generation */ +#include "sdp_generator.h" + +/* definitions */ +#define MAX_BUF 4096 + +/* configuration data*/ +#define MAIN_SECTION "Broadcaster" +#define SCENE_INIT "InitialScene" +#define RAP_TIMER "RAPPeriod" +#define PORT_CONFIG "ConfigPort" +#define PORT_MODIF "SceneUpdatePort" + +#define DEST_SECTION "Destination" +#define DEST_ADDRESS "IP" +#define PORT_OUTPUT "Port" + +#define FEEDBACK_SECTION "Feedback" +#define IP_FEEDBACK "IP" +#define PORT_FEEDBACK "Port" + +/* data struct on the server side */ +typedef struct config_data +{ + const char *rap_timer; + const char *scene_init_file; + const char *modif_input_port; + const char *config_input_port; + + const char *feedback_ip; + const char *feedback_port; + + const char *dest_ip; + const char *dest_port; +} CONF_Data; + +typedef struct tcp_input +{ + u16 port; // server port + u32 *config_flag; // indicates whether the tcp server waits for configuration data + // GF_Socket *socket; // socket tcp for the GUI interface + u32 *RAPtimer; + CONF_Data *config; + u32 status; + int debug; +} TCP_Input; + +typedef struct rap_input +{ + GF_Mutex *carrousel_mutex; + u32 *RAPtimer; + PNC_CallbackData *data; + u32 status; +} RAP_Input; + +/*void command_line_parsing(int* argc, const char** argv, int *tcp_port, const char *config_file, int *config_flag); +int server_command_line(char *arg_a, char *arg_b, char *value, int argument);*/ +u32 tcp_server(void *par); +u32 RAP_send(void *par); +void print_usage(void); diff --git a/applications/testapps/broadcaster/broadcaster_config.cfg b/applications/testapps/broadcaster/broadcaster_config.cfg new file mode 100644 index 0000000..50c802d --- /dev/null +++ b/applications/testapps/broadcaster/broadcaster_config.cfg @@ -0,0 +1,16 @@ +[Broadcaster] +InitialScene=/var/www/initial.bt +RAPPeriod=2 +ConfigPort=5500 +SceneUpdatePort=8100 + +[Destination] +#IP=233.64.133.10 +#IP=137.194.232.99 +IP=127.0.0.1 +Port=7100 + +[Feedback] +#IP=137.194.232.99 +IP=127.0.0.1 +Port=5758 diff --git a/applications/testapps/broadcaster/debug.c b/applications/testapps/broadcaster/debug.c new file mode 100644 index 0000000..a2a28aa --- /dev/null +++ b/applications/testapps/broadcaster/debug.c @@ -0,0 +1,24 @@ +#include "debug.h" +#include +#include + +static int _broadcaster_debug = 0; + +void setDebugMode(int mode) +{ + _broadcaster_debug = mode; +} + +int getDebugMode() +{ + return _broadcaster_debug; +} + +void dprintf(debugMode debug, const char *msg, ...) +{ + va_list ap; + va_start( ap, msg ); + if ((debug & _broadcaster_debug) == debug) + vfprintf(stderr, msg, ap); + va_end(ap); +} diff --git a/applications/testapps/broadcaster/debug.h b/applications/testapps/broadcaster/debug.h new file mode 100644 index 0000000..4b4da6e --- /dev/null +++ b/applications/testapps/broadcaster/debug.h @@ -0,0 +1,18 @@ +#ifndef _BROADCASTER_DEBUG_H +#define _BROADCASTER_DEBUG_H + +typedef enum _debugMode { + DEBUG_broadcaster = 1, + DEBUG_RTP_serv_generator = 2, + DEBUG_RTP_serv_packetizer =4, + DEBUG_RTP_serv_sender = 8, + DEBUG_sdp_generator = 16 +} debugMode; + +void setDebugMode(int mode); + +int getDebugMode(); + +void dprintf(debugMode debug, const char *msg, ...); + +#endif diff --git a/applications/testapps/broadcaster/france.mp4 b/applications/testapps/broadcaster/france.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..fbfea0a411a299aeca7614fd5f4ad2d4e49424f0 GIT binary patch literal 9131 zcmdVf4Ukpkc>v%GB0-Ca7RhZSik2w;lu$*B2@;B^_!Fcm4mHGpt`v3o5mtsErNmf5 zkx^V&Se8Y0Vej1?|4O;{?%v&)l(9;Qp@u3NRBEXjgI19mV$d4w^PW8@aj4UoOvi+o z%X7bTzVm+X_kQ0w_j1W(PX5M}iiuSlk8N1IKa;+wpJZ=~&)((^BJxZ~S7fX}8r zow|kN9pA)=)4?I!KsmHOXuJ=&E**Cbjn!Vqom@__+m~@OmvSSkxsYDf*KjT)-tC#} zeS3Htjom(nEvfaXvl;!WIFpsUg-duQBfs-Gh+m<4wO_z~{8}cvB;sGE-IvoDd2rb=9Nz9ggQbirJx#)pt?dsw3Wv zgN(RSwZkdg$Zs;nzmakMST5n$xt)JOb?T7w(is2p)QeN?z1SBW!?=^`pIm3o)mydI zp?V9gO|^P<^y40$)VZ%ZPNs7mU*rIukhVXc+B=i2ou0{-p6BdLwp9)*d(iQf6KI`R zszd9wG>=w&SGG{!l}-E}<=(p3^{?{V+G4coyRs*(N9}fA$>?WZE6gXcNXJ%`sSYb1 zr!iM7V-+8z_$%hpu@#kUSK)SU*Q<;=eSI^?RXAizf5-dJ`U9G#?h?h&GP9_ zdDix#b&fb~&6HEyLo`m?PiX8m`!Vt;_vI*xx7;{o?`xbd59M9Fg!5^gYxYn*5|`-T zQ~O?uQNEAHFS~a6NZv!al-=jc$FqsEndfG%<~BBPJJn%%#Bb+b{y<(mxRK^u{yqou zQBL3wS-~e6asQQaDqHszTlg$@(Q_=;r~L2glHu!}^(lM))n>KTp*G_FBK4OXqP>qX zAJ-;+*lD}xX!LJCiu$$p;x#;$)2Sx4i_`Our{{Ojeyx>HyL}w{sr?ihzumgVer&go zS4JHDVqdnO#@QUexv6QKm2zr7F_Wz`R>Z68OV5!yeG?7b2?vsjg|Zvt5Wx* z?&~~XuMW|#UhKHOUJi+JOB}_WjvsKO_DkZGX?<6%=QCW!E&BDMbM=u|IF4-`&L30$ zW&1xl?sKeuwzhp!uO8)S%OUnl{X)K($*zv^UP%2ZhiV&Vb>w5;tya(SKU3d`fB#v0 zf)V#|MqP4rP5FULc1>I-=QWYHc{ODC29Kl|4c0X3(QpRUv0+fE&xGWBTyMWNcy`79 zY-q9$o|g?Rlv~4E>f5k{m(o4hKAMZ^nuhy%YwGQ+*ZylR;8M=xDyl`a8|ByTnnvr= z{tt|}%ekG#UfY$%SZmC7pD$~_!YQeqM{DP5e}i?5_6GVqSZmJhmt?Z*%scX4SIN_P z7f)j~FJ$B=_PUpO0YBiynQT*E4rAndJ|E!8nQX2P?f2Ypik-Vmo&K9@P~J;9mv{3G zTF-ocKF4ls<|G<3U&WO)xANVb!-c$oa?D>vb<0QGJ9q`Hd0uYiSu}omCI|914xqZ^ zPvlMP!I6yhSF_x!Jc8Rim*tgvg!0K**EY|^oO-k^qF0->%H2uz&Z%45-*PJdCUq{o z+HRp-+w{q)f7>)h9CJ(B^3IuSn|b8&6f^fgs{I+CAIbQCm7c$mwT`QIPA%Gwp)p#2 z&dHshSGjBWl=c{I;b^)qa^~9lBuAueYnPlqkM>gTY`(}-`7)2=F81Ia>-&!Jx^h1U zP@gt+YudrD@o9?PWQ?|p_&7(gO#7`V<`Whf{Wo(k<=ST7HQ57g)+W)|N!-uzCC9sS zr#$SV#P?|Y))y$B*2mKPH&70(4|6;p;$*u2bJMvZZQED58?^6X)Nc_dG1fEM^BDcV z&G~en<`yv4Zy{qnUE6vc7xUWGs~G*mIlP*&9^Yc*6W2S}YJVo{V!tN&#yGR)n@cEk^_OjY+JuKPCetEuXo8=&8rJd1Ik4&(`pal=vU%h9Rh znAM)Z<7m#UvESt0dK8ziCus)%1JNO2@FTKt^ zw2$*g^53-Ir*+NuVu5liS=YRJl#G!d!FtNKbT4~w2D{Q)=HyV4dwvMjKX3n+)GeM1 zC2NpBkLs6K=aLxtv#17nbuOt}zF(>ul#H1_nitSsEU8%%-#*T5*S?f7uRrIu&VKPc zDV?irj-_)L^D|a%9|tk=`?7d_XzX|{mCm5Giu1`l^^fOT>3rHpiPuq%`N=egd?k&O zpUt>VO-j}`o|`4P=NHi!@mwu^p3$!-XHl&a4@-|{I4_eezDM_O(Hi8R<_9#d#O?gG z_6w;m(OmL-X}$CBGOpi8>z;p;?@%2QU#42*pG@7v-P(^)-^8CW#(#xdXzV2JYng1b z`WHj%k!a3EF`I{QCoiV`(>#Jd9V~!d+~p+7+8J*_Oz&fyc3iC$gHSatW{H-Ml_E@`(0z^xSHR zaqGC2aed_VJw{&hxQKVq7{xg>X3-kAY~W088S{4kv`pqm-os(6 zPmOs;JLc#9YEkQ=`>tg@hcec|{nhdS2Qm5&H~;}gDbrpZik=(}fQU|7 zPQ*UQ?WS>aucgX6_DxQnFaNUobl`!PPBBk$aKJe_B!p2`8* z>YAK4R?)GXITcSzjqxKt`!PQEWB=v`^B4}Hoa6gNv0K{i(s@4iO|HK>T7!rm>ywN9 z_AfMM;h$2?C3l8)fzdC%Z^dRY&%!})hq_re^SUttzU^EO`3Dpv4T zdSCDyiSHwYD|rKlrHUQjzYFFR-`@&zlSu zVYG+w4ysk*W)9%DnBk@3ME%rt?NkopBz~D{lz1%%YU>m0xwa3#Z(|&K{A7$*b&3zsK=> z-S3$@Jm0!=sJ6YbJj-AC9o04Q{Hv*?`PK~L(V6VBg|x4hwb1@swvnz~CVuf^{km}s zjUV5SYR0jGlWA|%m|t-L_z*lwjafe-)Bq4tc`fjaXO#R^jNjkf0_0Aj9-S& z#DCrWKE0x52j}})*YMNEKRD0N^8Kgf`2T$_=6$F!{ifHJ?Ds9---VhTDu>_p zK8TpVZH)iR^@qy+lgBGbGCQ-XDyc-;=Rn${XI9NjRwF$=Y|8Y(2lpFzlWd&J z95(+Xe|MYTr^`{9ldp~=@#paQ-7`auX*hO%_by#Edy6(FInmiCM(OL=jh)AmOyk&r lSM)!4v^ehAjnfY5A3Lx2?G;rM+4I_quDbfdE3f*~{{dH};XMEV literal 0 HcmV?d00001 diff --git a/applications/testapps/broadcaster/meteo_local.xmt b/applications/testapps/broadcaster/meteo_local.xmt new file mode 100644 index 0000000..7749589 --- /dev/null +++ b/applications/testapps/broadcaster/meteo_local.xmt @@ -0,0 +1,393 @@ + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ diff --git a/applications/testapps/broadcaster/sdp_generator.c b/applications/testapps/broadcaster/sdp_generator.c new file mode 100644 index 0000000..2547037 --- /dev/null +++ b/applications/testapps/broadcaster/sdp_generator.c @@ -0,0 +1,67 @@ +#include "sdp_generator.h" +#include "debug.h" + +int sdp_generator(PNC_CallbackData *data, char *ip_dest, char *sdp_fmt) +{ + GF_SceneEngine *codec; + GF_ESD *esd = NULL; + u32 size,size64; + char *buffer; + char buf64[5000]; + FILE *fp; + int ret; + char temp[5000]; + u16 port; + u32 socket_type; + + gf_sk_get_local_info(data->chan->rtp, &port, &socket_type); + + fp = gf_fopen("broadcaster.sdp", "w+"); + if(fp == NULL) { + fprintf(stderr, "Cannot open SDP file broadcaster.sdp\n"); + exit(1); + } + + ret = gf_fwrite("v=0\n", 1, 4, fp); + sprintf(temp, "o=GpacBroadcaster 3326096807 1117107880000 IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest); + ret = gf_fwrite(temp, 1, strlen(temp), fp); + + ret = gf_fwrite("s=MPEG4Broadcaster\n", 1, 19, fp); + + sprintf(temp, "c=IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest); + ret = gf_fwrite(temp, 1, strlen(temp), fp); + + ret = gf_fwrite("t=0 0\n", 1, 6, fp); + + codec = (GF_SceneEngine *) data->codec; + if (codec) { + buffer = NULL; + size = 0; + gf_odf_desc_write((GF_Descriptor *) codec->ctx->root_od, &buffer, &size); + esd = gf_list_get(codec->ctx->root_od->ESDescriptors, 0); + + size64 = gf_base64_encode((unsigned char *) buffer, size, (unsigned char *) buf64, 2000); + buf64[size64] = 0; + free(buffer); + + sprintf(temp, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"\n", buf64); + ret = gf_fwrite(temp, 1, strlen(temp), fp); + } + + sprintf(temp, "m=application %d RTP/AVP 96\n", port); + ret = gf_fwrite(temp, 1, strlen(temp), fp); + + ret = gf_fwrite("a=rtpmap:96 mpeg4-generic/1000\n", 1, 31, fp); + + if (esd) { + sprintf(temp, "a=mpeg4-esid:%d\n", esd->ESID); + ret = gf_fwrite(temp, 1, strlen(temp), fp); + } + + sprintf(temp, "%s\n", sdp_fmt); + ret = gf_fwrite(temp, 1, strlen(temp), fp); + fflush(fp); + gf_fclose(fp); + dprintf(DEBUG_sdp_generator, "SDP file generated in broadcaster.sdp\n"); + return GF_OK; +} diff --git a/applications/testapps/broadcaster/sdp_generator.h b/applications/testapps/broadcaster/sdp_generator.h new file mode 100644 index 0000000..9e5d155 --- /dev/null +++ b/applications/testapps/broadcaster/sdp_generator.h @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include +#include +#include "RTP_serv_generator.h" + +/* structure definitions */ +struct __tag_bifs_engine +{ + GF_SceneGraph *sg; + GF_SceneManager *ctx; + GF_SceneLoader load; + void *calling_object; + GF_StreamContext *sc; + + GF_BifsEncoder *bifsenc; + u32 stream_ts_res; + /* TODO: maybe the currentAUCount should be a GF_List of u32 + to capture the number of AU per input BIFS stream */ + u32 currentAUCount; + + char encoded_bifs_config[20]; + u32 encoded_bifs_config_size; +}; + +int sdp_generator(PNC_CallbackData *data, char *ip_dest, char *sdp_fmt); diff --git a/applications/testapps/dmbrs/dmbrs.dsp b/applications/testapps/dmbrs/dmbrs.dsp new file mode 100644 index 0000000..a94c742 --- /dev/null +++ b/applications/testapps/dmbrs/dmbrs.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="dmbrs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=dmbrs - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dmbrs.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dmbrs.mak" CFG="dmbrs - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dmbrs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "dmbrs - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dmbrs - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 zlib.lib winmm.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/dmbrs.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "dmbrs - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 zlib.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/dmbrs.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "dmbrs - Win32 Release" +# Name "dmbrs - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Target +# End Project diff --git a/applications/testapps/dmbrs/main.c b/applications/testapps/dmbrs/main.c new file mode 100644 index 0000000..a9b64a7 --- /dev/null +++ b/applications/testapps/dmbrs/main.c @@ -0,0 +1,251 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2000-2012 + * All rights reserved + * + * This file is part of GPAC / DMB application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include + +void save_ts(char *filename, unsigned char *data) +{ + FILE *ts_out = gf_fopen(filename,"a+b"); + gf_fwrite(data, 1, 188, ts_out); + gf_fclose(ts_out); +} +void save_rs_0(char *filename, unsigned char *data) +{ + FILE *rs_out = gf_fopen(filename,"a+b"); + gf_fwrite(data, 1, 204, rs_out); + gf_fclose(rs_out); +} + +void RS_Interleaver(GF_BitStream *bs, char *out_name) +{ + u8 *tmp; + u8 ts0[204], ts1[204], ts2[204], ts3[204], ts4[204], ts5[204], ts6[204], ts7[204], ts8[204], ts9[204], ts10[204], ts11[204]; + u8 *ts[12] = { ts0, ts1, ts2, ts3, ts4, ts5, ts6, ts7, ts8, ts9, ts10, ts11 }; + u8 rs[204]; + u32 i; + u64 bs_data; + u32 k; + + memset(ts[0], 0xFF, 204); + ts[0][0] = 0x47; + memset(ts[1], 0xFF, 204); + ts[1][0] = 0x47; + memset(ts[2], 0xFF, 204); + ts[2][0] = 0x47; + memset(ts[3], 0xFF, 204); + ts[3][0] = 0x47; + memset(ts[4], 0xFF, 204); + ts[4][0] = 0x47; + memset(ts[5], 0xFF, 204); + ts[5][0] = 0x47; + memset(ts[6], 0xFF, 204); + ts[6][0] = 0x47; + memset(ts[7], 0xFF, 204); + ts[7][0] = 0x47; + memset(ts[8], 0xFF, 204); + ts[8][0] = 0x47; + memset(ts[9], 0xFF, 204); + ts[9][0] = 0x47; + memset(ts[10], 0xFF, 204); + ts[10][0] = 0x47; + + k = 11; + bs_data = gf_bs_available(bs); + while (bs_data > 188 || k > 0) { + + gf_bs_read_data(bs, ts[11], 188); + if (bs_data == 0) { + memset(ts[11], 0xFF, 204); + ts[11][0] = 0x47; + k--; + } + bs_data = gf_bs_available(bs); + + for (i=0; i<(17*12); i+=12) { // 1 paquet RS + + rs[i] = ts[11][i]; + if (rs[0] != 0x47) { + printf ("error ts sync byte"); + } + rs[i+1] = ts[10][i+1]; + rs[i+2] = ts[9][i+2]; + rs[i+3] = ts[8][i+3]; + rs[i+4] = ts[7][i+4]; + rs[i+5] = ts[6][i+5]; + rs[i+6] = ts[5][i+6]; + rs[i+7] = ts[4][i+7]; + rs[i+8] = ts[3][i+8]; + rs[i+9] = ts[2][i+9]; + rs[i+10] = ts[1][i+10]; + rs[i+11] = ts[0][i+11]; + } + + if (rs[0] != 0x47) { + printf("error in output TS\n"); + } else { + save_rs_0(out_name, rs); + } + + tmp = ts[0]; + ts[0] = ts[1]; + ts[1] = ts[2]; + ts[2] = ts[3]; + ts[3] = ts[4]; + ts[4] = ts[5]; + ts[5] = ts[6]; + ts[6] = ts[7]; + ts[7] = ts[8]; + ts[8] = ts[9]; + ts[9] = ts[10]; + ts[10] = ts[11]; + ts[11] = tmp; + } +} + +void RS_Deinterleaver(GF_BitStream *bs, char *out_name) +{ + u8 rs0[204], rs1[204], rs2[204], rs3[204], rs4[204], rs5[204], rs6[204], rs7[204], rs8[204], rs9[204], rs10[204], rs11[204]; + u8 *rs[12] = { rs0, rs1, rs2, rs3, rs4, rs5, rs6, rs7, rs8, rs9, rs10, rs11 }; + u8 *tmp; + u8 buf[204]; + u32 i; + u64 bs_data; + u32 k = 0; + + memset(rs[0], 0, 204); + memset(rs[1], 0, 204); + memset(rs[2], 0, 204); + memset(rs[3], 0, 204); + memset(rs[4], 0, 204); + memset(rs[5], 0, 204); + memset(rs[6], 0, 204); + memset(rs[7], 0, 204); + memset(rs[8], 0, 204); + memset(rs[9], 0, 204); + memset(rs[10], 0, 204); + memset(rs[11], 0, 204); + + bs_data = gf_bs_available(bs); + while (bs_data > 204) { + u64 pos; + k++; +// printf("TS Packet Number: %d\r", k); + + pos = gf_bs_get_position(bs); + gf_bs_read_data(bs, buf, 204); + bs_data = gf_bs_available(bs); + + while ((buf[0] != 0x47) && (bs_data > 0)) { + printf("error in input TS %d\n", k); + //return; + pos++; + gf_bs_seek(bs, pos); + gf_bs_read_data(bs, buf, 204); + bs_data = gf_bs_available(bs); + } + + for (i=0; i<(17*12); i+=12) { // 1 paquet + rs[0][i] = buf[i]; + rs[1][i+1] = buf[i+1]; + rs[2][i+2] = buf[i+2]; + rs[3][i+3] = buf[i+3]; + rs[4][i+4] = buf[i+4]; + rs[5][i+5] = buf[i+5]; + rs[6][i+6] = buf[i+6]; + rs[7][i+7] = buf[i+7]; + rs[8][i+8] = buf[i+8]; + rs[9][i+9] = buf[i+9]; + rs[10][i+10] = buf[i+10]; + rs[11][i+11] = buf[i+11]; + } + if (k >= 12) { + if (rs[11][0] != 0x47) { + printf("error in output TS\n"); + } else { + save_ts(out_name, rs[11]); + } + } + tmp = rs[11]; + rs[11] = rs[10]; + rs[10] = rs[9]; + rs[9] = rs[8]; + rs[8] = rs[7]; + rs[7] = rs[6]; + rs[6] = rs[5]; + rs[5] = rs[4]; + rs[4] = rs[3]; + rs[3] = rs[2]; + rs[2] = rs[1]; + rs[1] = rs[0]; + rs[0] = tmp; + } +} + +void main(int argc, char **argv) +{ + FILE *in; + GF_BitStream *bs; + + /* generation d'un TS aléatoire */ + /* + if ((in=gf_fopen(argv[1], "wb")) == NULL) { + printf( "Impossible d'ouvrir %s en lecture.\n", argv[1]); + } + { + char buffer[188]; + u32 j, i, nb_packets = 300; + for (i = 0; i < nb_packets; i++) { + buffer[0] = 0x47; + for (j = 1; j <188; j++) { + buffer[j] = rand();//j; + } + gf_fwrite(buffer, 1, 188, in); + } + } + gf_fclose(in); + if ((in=gf_fopen(argv[1], "rb")) == NULL) { + printf( "Impossible d'ouvrir %s en lecture.\n", argv[1]); + } + + bs = gf_bs_from_file(in, GF_BITSTREAM_READ); + if (bs == NULL) return; + + RS_Interleaver(bs, argv[2]); + gf_fclose(in); + gf_bs_del(bs); + */ + + + if ((in=gf_fopen(argv[1], "rb")) == NULL) { + printf( "Impossible d'ouvrir %s en lecture.\n", argv[1]); + } + + bs = gf_bs_from_file(in, GF_BITSTREAM_READ); + if (bs == NULL) return; + + RS_Deinterleaver(bs, argv[2]); + gf_fclose(in); + gf_bs_del(bs); + +} \ No newline at end of file diff --git a/applications/testapps/fmp4demux/Makefile b/applications/testapps/fmp4demux/Makefile new file mode 100644 index 0000000..b736725 --- /dev/null +++ b/applications/testapps/fmp4demux/Makefile @@ -0,0 +1,50 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/testapps/fmp4demux + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o + +LINKFLAGS=-L../../../bin/gcc +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=fmp4demux$(EXE) +else +EXT= +PROG=fmp4demux +endif +LINKFLAGS+=-lgpac + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/testapps/fmp4demux/build.sh b/applications/testapps/fmp4demux/build.sh new file mode 100755 index 0000000..d1dd330 --- /dev/null +++ b/applications/testapps/fmp4demux/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_file.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB diff --git a/applications/testapps/fmp4demux/fmp4demux.sln b/applications/testapps/fmp4demux/fmp4demux.sln new file mode 100644 index 0000000..26bfd3d --- /dev/null +++ b/applications/testapps/fmp4demux/fmp4demux.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmp4demux", "fmp4demux.vcxproj", "{978A2D9F-E44F-4073-8032-333563BCC160}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.ActiveCfg = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.Build.0 = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.ActiveCfg = Release|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/applications/testapps/fmp4demux/fmp4demux.vcxproj b/applications/testapps/fmp4demux/fmp4demux.vcxproj new file mode 100644 index 0000000..e33b75b --- /dev/null +++ b/applications/testapps/fmp4demux/fmp4demux.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {BEBEB264-EEA8-4FCF-9467-2E7988DD923B} + fmp4demux + + + + Application + v110 + false + MultiByte + + + Application + v100 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + AllRules.ruleset + + + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + AllRules.ruleset + + + + + + .\Debug/fmp4demux.tlb + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + true + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + MachineX86 + + + true + .\Debug/fmp4demux.bsc + + + + + .\Release/fmp4demux.tlb + + + + MaxSpeed + OnlyExplicitInline + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/fmp4demux.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) + .\Release/fmp4demux.pdb + Console + MachineX86 + + + true + .\Release/fmp4demux.bsc + + + + + + \ No newline at end of file diff --git a/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters b/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters new file mode 100644 index 0000000..5ea66a7 --- /dev/null +++ b/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters @@ -0,0 +1,140 @@ + + + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + isoff + + + others + + + + + {c9a8f639-328c-4505-be50-4859357c2c00} + + + {e5ca7285-ca00-49d8-ac81-dff3d494be9a} + + + \ No newline at end of file diff --git a/applications/testapps/fmp4demux/main.c b/applications/testapps/fmp4demux/main.c new file mode 100644 index 0000000..8c6c22a --- /dev/null +++ b/applications/testapps/fmp4demux/main.c @@ -0,0 +1,315 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2013- + * All rights reserved + * + * This file is part of GPAC / sample MP4 demultiplexing application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +//#define GPAC_HAVE_CONFIG_H + +#include +#include +#include + +#define BUFFER_BLOC_SIZE 1000 +#define MAX_BUFFER_SIZE 200000 + +typedef struct iso_progressive_reader { + + /* data buffer to be read by the parser */ + u8 *data; + /* size of the data buffer */ + u32 data_size; + /* number of valid bytes in the buffer */ + u32 valid_data_size; + /* URL used to pass a buffer to the parser */ + char data_url[256]; + + /* The ISO file structure created for the parsing of data */ + GF_ISOFile *movie; + + /* Mutex to protect the reading from concurrent adding of media data */ + GF_Mutex *mutex; + + /* Boolean indicating if the thread should stop */ + volatile Bool do_run; + + /* Boolean state to indicate if the needs to be parsed */ + Bool refresh_boxes; + + /* id of the track in the ISO to be read */ + u32 track_id; + +} ISOProgressiveReader; + + +static u32 iso_progressive_read_thread(void *param) +{ + ISOProgressiveReader *reader = (ISOProgressiveReader *)param; + u32 track_number; + GF_ISOSample *iso_sample; + u32 samples_processed; + u32 sample_index; + u32 sample_count; + + samples_processed = 0; + sample_count = 0; + track_number = 0; + /* samples are numbered starting from 1 */ + sample_index = 1; + + while (reader->do_run == GF_TRUE) { + + /* we can only parse if there is a movie */ + if (reader->movie) { + + /* block the data input until we are done in the parsing */ + gf_mx_p(reader->mutex); + + /* get the track number we want */ + if (track_number == 0) { + track_number = gf_isom_get_track_by_id(reader->movie, reader->track_id); + } + + /* only if we have the track number can we try to get the sample data */ + if (track_number != 0) { + u32 new_sample_count; + u32 di; /*descriptor index*/ + + /* let's see how many samples we have since the last parsed */ + new_sample_count = gf_isom_get_sample_count(reader->movie, track_number); + if (new_sample_count > sample_count) { + /* New samples have been added to the file */ + fprintf(stdout, "Found %d new samples (total: %d)\n", new_sample_count - sample_count, new_sample_count); + if (sample_count == 0) { + sample_count = new_sample_count; + } + } + if (sample_count == 0) { + /* no sample yet, let the data input force a reparsing of the data */ + reader->refresh_boxes = GF_TRUE; + /*let the reader push new data */ + gf_mx_v(reader->mutex); + //gf_sleep(1000); + } else { + /* we have some samples, lets keep things stable in the parser for now and + don't let the data input force a reparsing of the data */ + reader->refresh_boxes = GF_FALSE; + + /* let's analyze the samples we have parsed so far one by one */ + iso_sample = gf_isom_get_sample(reader->movie, track_number, sample_index, &di); + if (iso_sample) { + /* if you want the sample description data, you can call: + GF_Descriptor *desc = gf_isom_get_decoder_config(reader->movie, reader->track_handle, di); + */ + + samples_processed++; + /*here we dump some sample info: samp->data, samp->dataLength, samp->isRAP, samp->DTS, samp->CTS_Offset */ + fprintf(stdout, "Found sample #%5d (#%5d) of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\r", sample_index, samples_processed, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset); + sample_index++; + + /*release the sample data, once you're done with it*/ + gf_isom_sample_del(&iso_sample); + + /* once we have read all the samples, we can release some data and force a reparse of the input buffer */ + if (sample_index > sample_count) { + u64 new_buffer_start; + u64 missing_bytes; + + fprintf(stdout, "\nReleasing unnecessary buffers\n"); + /* release internal structures associated with the samples read so far */ + gf_isom_reset_tables(reader->movie, GF_TRUE); + +#if 1 + /* release the associated input data as well */ + gf_isom_reset_data_offset(reader->movie, &new_buffer_start); + if (new_buffer_start) { + u32 offset = (u32)new_buffer_start; + memmove(reader->data, reader->data+offset, reader->data_size-offset); + reader->valid_data_size -= offset; + } + sprintf(reader->data_url, "gmem://%d@%p", reader->valid_data_size, reader->data); + gf_isom_refresh_fragmented(reader->movie, &missing_bytes, reader->data_url); +#endif + + /* update the sample count and sample index */ + sample_count = new_sample_count - sample_count; + assert(sample_count == 0); + sample_index = 1; + } + } else { + GF_Err e = gf_isom_last_error(reader->movie); + fprintf(stdout, "Could not get sample %s\r", gf_error_to_string(e)); + } + /* and finally, let the data reader push more data */ + gf_mx_v(reader->mutex); + } + } + } else { + //gf_sleep(1); + } + } + return 0; +} + +int main(int argc, char **argv) +{ + /* The ISO progressive reader */ + ISOProgressiveReader reader; + /* Error indicator */ + GF_Err e; + /* input file to be read in the data buffer */ + FILE *input; + /* number of bytes read from the file at each read operation */ + u32 read_bytes; + /* number of bytes read from the file (total) */ + u64 total_read_bytes; + /* size of the input file */ + u64 file_size; + /* number of bytes required to finish the current ISO Box reading (not used here)*/ + u64 missing_bytes; + /* Thread used to run the ISO parsing in */ + GF_Thread *reading_thread; + /* Return value for the program */ + int ret = 0; + + /* Usage */ + if (argc != 2) { + fprintf(stdout, "Usage: %s filename\n", argv[0]); + return 1; + } + + /* Initializing GPAC framework */ + /* Enables GPAC memory tracking in debug mode only */ +#if defined(DEBUG) || defined(_DEBUG) + gf_sys_init(GF_TRUE); + gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); + gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); +#else + gf_sys_init(GF_FALSE); + gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); +#endif + + /* This is an input file to read data from. Could be replaced by any other method to retrieve the data (e.g. JavaScript, socket, ...)*/ + input = gf_fopen(argv[1], "rb"); + if (!input) { + fprintf(stdout, "Could not open file %s for reading.\n", argv[1]); + gf_sys_close(); + return 1; + } + + gf_fseek(input, 0, SEEK_END); + file_size = gf_ftell(input); + gf_fseek(input, 0, SEEK_SET); + + /* Initializing the progressive reader */ + memset(&reader, 0, sizeof(ISOProgressiveReader)); + reading_thread = gf_th_new("ISO reading thread"); + reader.mutex = gf_mx_new("ISO Segment"); + reader.do_run = GF_TRUE; + /* we want to parse the first track */ + reader.track_id = 1; + /* start the async parsing */ + gf_th_run(reading_thread, iso_progressive_read_thread, &reader); + + /* start the data reading */ + reader.data_size = BUFFER_BLOC_SIZE; + reader.data = (u8 *)gf_malloc(reader.data_size); + reader.valid_data_size = 0; + total_read_bytes = 0; + while (1) { + /* block the parser until we are done manipulating the data buffer */ + gf_mx_p(reader.mutex); + + if (reader.valid_data_size + BUFFER_BLOC_SIZE > MAX_BUFFER_SIZE) { + /* regulate the reader to limit the max buffer size and let some time to the parser to release buffer data */ + fprintf(stdout, "Buffer full (%d/%d)- waiting to read next data \r", reader.valid_data_size, reader.data_size); + gf_mx_v(reader.mutex); + //gf_sleep(10); + } else { + /* make sure we have enough space in the buffer to read the next bloc of data */ + if (reader.valid_data_size + BUFFER_BLOC_SIZE > reader.data_size) { + reader.data = (u8 *)gf_realloc(reader.data, reader.data_size + BUFFER_BLOC_SIZE); + reader.data_size += BUFFER_BLOC_SIZE; + } + + /* read the next bloc of data and update the data buffer url */ + read_bytes = fread(reader.data+reader.valid_data_size, 1, BUFFER_BLOC_SIZE, input); + total_read_bytes += read_bytes; + fprintf(stdout, "Read "LLD" bytes of "LLD" bytes from input file %s (buffer status: %5d/%5d)\r", total_read_bytes, file_size, argv[1], reader.valid_data_size, reader.data_size); + if (read_bytes) { + reader.valid_data_size += read_bytes; + sprintf(reader.data_url, "gmem://%d@%p", reader.valid_data_size, reader.data); + } else { + /* end of file we can quit */ + gf_mx_v(reader.mutex); + break; + } + + /* if the file is not yet opened (no movie), open it in progressive mode (to update its data later on) */ + if (!reader.movie) { + /* let's initialize the parser */ + e = gf_isom_open_progressive(reader.data_url, 0, 0, &reader.movie, &missing_bytes); + if (reader.movie) { + gf_isom_set_single_moof_mode(reader.movie, GF_TRUE); + } + /* we can let parser try to work now */ + gf_mx_v(reader.mutex); + + if ((e == GF_OK || e == GF_ISOM_INCOMPLETE_FILE) && reader.movie) { + /* nothing to do, this is normal */ + } else { + fprintf(stdout, "Error opening fragmented mp4 in progressive mode: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes); + ret = 1; + goto exit; + } + } else { + /* let inform the parser that the buffer has been updated with new data */ + e = gf_isom_refresh_fragmented(reader.movie, &missing_bytes, reader.data_url); + + /* we can let parser try to work now */ + gf_mx_v(reader.mutex); + + if (e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) { + fprintf(stdout, "Error refreshing fragmented mp4: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes); + ret = 1; + goto exit; + } + } + + //gf_sleep(1); + } + } + +exit: + /* stop the parser */ + reader.do_run = GF_FALSE; + gf_th_stop(reading_thread); + + /* clean structures */ + gf_th_del(reading_thread); + gf_mx_del(reader.mutex); + gf_free(reader.data); + gf_isom_close(reader.movie); + gf_fclose(input); + gf_sys_close(); + + return ret; +} diff --git a/applications/testapps/hevcbench/defbench.h b/applications/testapps/hevcbench/defbench.h new file mode 100644 index 0000000..2b233d6 --- /dev/null +++ b/applications/testapps/hevcbench/defbench.h @@ -0,0 +1,111 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2012 + * All rights reserved + * + * This file is part of GPAC - sample DASH library usage + * + */ + +#ifndef __DEF_BENCH_H__ +#define __DEF_BENCH_H__ + +#include +#include +#include +#define SDL_MAIN_HANDLED +#include +#include + +#define GL_GLEXT_PROTOTYPES + +#include +#include + + + + +#define GL_CHECK_ERR {s32 res = glGetError(); if (res) GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("GL Error %d file %s line %d\n", res, __FILE__, __LINE__)); } + +/*macros for GL proto and fun declaration*/ +#ifdef _WIN32_WCE +#define GLAPICAST * +#elif defined(WIN32) +#include +#define GLAPICAST APIENTRY * +#else +#define GLAPICAST * +#endif + +#define GLDECL(ret, funname, args) \ +typedef ret (GLAPICAST proc_ ## funname)args; \ +extern proc_ ## funname funname; \ + +#define GLDECL_STATIC(funname) proc_ ## funname funname = NULL + +#if defined GPAC_USE_TINYGL +//no extensions with TinyGL +#elif defined (GPAC_USE_GLES1X) +//no extensions with OpenGL ES +#elif defined(WIN32) || defined (GPAC_CONFIG_WIN32) +#define LOAD_GL_FUNCS +#define GET_GLFUN(funname) funname = (proc_ ## funname) wglGetProcAddress(#funname) +#elif defined(CONFIG_DARWIN_GL) +extern void (*glutGetProcAddress(const GLubyte *procname))( void ); +#define GET_GLFUN(funname) funname = (proc_ ## funname) glutGetProcAddress(#funname) +#else +#define LOAD_GL_FUNCS +extern void (*glXGetProcAddress(const GLubyte *procname))( void ); +#define GET_GLFUN(funname) funname = (proc_ ## funname) glXGetProcAddress(#funname) +#endif + + + +#define DEL_SHADER(_a) if (_a) { glDeleteShader(_a); _a = 0; } +#define DEL_PROGRAM(_a) if (_a) { glDeleteProgram(_a); _a = 0; } + + +GLDECL(GLuint, glCreateProgram, (void) ) +GLDECL(void, glDeleteProgram, (GLuint ) ) +GLDECL(void, glLinkProgram, (GLuint program) ) +GLDECL(void, glUseProgram, (GLuint program) ) +GLDECL(GLuint, glCreateShader, (GLenum shaderType) ) +GLDECL(void, glDeleteShader, (GLuint shader) ) +GLDECL(void, glShaderSource, (GLuint shader, GLsizei count, const char **string, const GLint *length) ) +GLDECL(void, glCompileShader, (GLuint shader) ) +GLDECL(void, glAttachShader, (GLuint program, GLuint shader) ) +GLDECL(void, glDetachShader, (GLuint program, GLuint shader) ) +GLDECL(void, glGetShaderiv, (GLuint shader, GLenum type, GLint *res) ) +GLDECL(void, glGetInfoLogARB, (GLuint shader, GLint size, GLsizei *rsize, const char *logs) ) +GLDECL(GLint, glGetUniformLocation, (GLuint prog, const char *name) ) +GLDECL(void, glUniform1f, (GLint location, GLfloat v0) ) +GLDECL(void, glUniform1i, (GLint location, GLint v0) ) +GLDECL(void, glActiveTexture, (GLenum texture) ) +GLDECL(void, glClientActiveTexture, (GLenum texture) ) +GLDECL(void, glGenBuffers, (GLsizei , GLuint *) ) +GLDECL(void, glDeleteBuffers, (GLsizei , GLuint *) ) +GLDECL(void, glBindBuffer, (GLenum, GLuint ) ) +GLDECL(void, glBufferData, (GLenum, int, void *, GLenum) ) +GLDECL(void, glBufferSubData, (GLenum, int, int, void *) ) +GLDECL(void *, glMapBuffer, (GLenum, GLenum) ) +GLDECL(void *, glUnmapBuffer, (GLenum) ) + + +#define GL_TEXTURE_RECTANGLE_EXT 0x84F5 + +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 + +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 + + +#endif diff --git a/applications/testapps/hevcbench/hevcbench.vcxproj b/applications/testapps/hevcbench/hevcbench.vcxproj new file mode 100644 index 0000000..9f677d3 --- /dev/null +++ b/applications/testapps/hevcbench/hevcbench.vcxproj @@ -0,0 +1,262 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F728CC84-A7D1-43D2-8A28-05CE9F2FE0D0} + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + ../../../bin/$(Platform)\$(Configuration)/ + ../../../bin/$(Platform)\$(Configuration)/ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ../../../bin/$(Platform)\$(Configuration)/ + ../../../bin/$(Platform)\$(Configuration)/ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + false + + + + + + + + + + Disabled + C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + .\obj\mp42ts_deb/$(ProjectName).pch + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + true + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + false + + + MachineX86 + + + true + + + + + + + + + + + Disabled + C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + .\obj\mp42ts_deb/$(ProjectName).pch + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + true + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + false + + + + + true + + + + + + + + + + + MaxSpeed + OnlyExplicitInline + C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\obj\mp42ts_rel/$(ProjectName).pch + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + $(IntDir)$(ProjectName).pdb + Console + false + + + MachineX86 + + + true + + + + + + + + + + + Full + AnySuitable + ../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\obj\mp42ts_rel/$(ProjectName).pch + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + Level3 + true + true + Speed + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + $(IntDir)$(ProjectName).pdb + Console + false + + + + + true + + + + + + + + {d3540754-e0cf-4604-ac11-82de9bd4d814} + + + + + + \ No newline at end of file diff --git a/applications/testapps/hevcbench/main.c b/applications/testapps/hevcbench/main.c new file mode 100644 index 0000000..83bd46e --- /dev/null +++ b/applications/testapps/hevcbench/main.c @@ -0,0 +1,858 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2012 + * All rights reserved + * + * This file is part of GPAC - sample DASH library usage + * + */ + +#include "defbench.h" + + + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) +# pragma comment(lib, "libLibOpenHevcWrapper") +#pragma comment(lib, "SDL2") +//#pragma comment(lib, "SDL2main") +#pragma comment(lib, "opengl32") +#endif + +//0: memcpy - 1: memmove - 2: u32 * cast and for loop copy of u32* - 3: memset 0 - 4: not touching the mapped buffer: 5: full memcpy, rely on stride in pixelstorei +#define COPY_TYPE 0 +//set to 1 to disable final gltexImage in PBO mode +#define NO_TEX 0 + + +SDL_Window *window = NULL; +SDL_GLContext *glctx= NULL; +SDL_Renderer *render= NULL; +GLint txid[3]; +u8 *pY = NULL; +u8 *pU = NULL; +u8 *pV = NULL; +u32 width = 0; +u32 height = 0; +u32 size=0; +u32 bpp=8; +u32 Bpp=1; +GLint memory_format=GL_UNSIGNED_BYTE; +GLint pixel_format=GL_LUMINANCE; +GLint texture_type=GL_TEXTURE_RECTANGLE_EXT; +u32 gl_nb_frames = 1; +u64 gl_upload_time = 0; +u64 gl_draw_time = 0; +Bool pbo_mode = GF_TRUE; +Bool first_tx_load = GF_FALSE; +Bool use_vsync=0; + +GLint glsl_program; +GLint vertex_shader; +GLint fragment_shader; + +GLint pbo_Y=0; +GLint pbo_U=0; +GLint pbo_V=0; + +GLDECL_STATIC(glActiveTexture); +GLDECL_STATIC(glClientActiveTexture); +GLDECL_STATIC(glCreateProgram); +GLDECL_STATIC(glDeleteProgram); +GLDECL_STATIC(glLinkProgram); +GLDECL_STATIC(glUseProgram); +GLDECL_STATIC(glCreateShader); +GLDECL_STATIC(glDeleteShader); +GLDECL_STATIC(glShaderSource); +GLDECL_STATIC(glCompileShader); +GLDECL_STATIC(glAttachShader); +GLDECL_STATIC(glDetachShader); +GLDECL_STATIC(glGetShaderiv); +GLDECL_STATIC(glGetInfoLogARB); +GLDECL_STATIC(glGetUniformLocation); +GLDECL_STATIC(glUniform1f); +GLDECL_STATIC(glUniform1i); +GLDECL_STATIC(glGenBuffers); +GLDECL_STATIC(glDeleteBuffers); +GLDECL_STATIC(glBindBuffer); +GLDECL_STATIC(glBufferData); +GLDECL_STATIC(glBufferSubData); +GLDECL_STATIC(glMapBuffer); +GLDECL_STATIC(glUnmapBuffer); + + +static char *glsl_yuv_shader = "\ + #version 140\n\ + #extension GL_ARB_texture_rectangle : enable\n\ + uniform sampler2DRect y_plane;\ + uniform sampler2DRect u_plane;\ + uniform sampler2DRect v_plane;\ + uniform float width;\ + uniform float height;\ + const vec3 offset = vec3(-0.0625, -0.5, -0.5);\ + const vec3 R_mul = vec3(1.164, 0.000, 1.596);\ + const vec3 G_mul = vec3(1.164, -0.391, -0.813);\ + const vec3 B_mul = vec3(1.164, 2.018, 0.000);\ + out vec4 FragColor;\ + void main(void) \ + {\ + vec2 texc;\ + vec3 yuv, rgb;\ + texc = gl_TexCoord[0].st;\ + texc.y = 1.0 - texc.y;\ + texc.x *= width;\ + texc.y *= height;\ + yuv.x = texture2DRect(y_plane, texc).r; \ + texc.x /= 2.0;\ + texc.y /= 2.0;\ + yuv.y = texture2DRect(u_plane, texc).r; \ + yuv.z = texture2DRect(v_plane, texc).r; \ + yuv += offset; \ + rgb.r = dot(yuv, R_mul); \ + rgb.g = dot(yuv, G_mul); \ + rgb.b = dot(yuv, B_mul); \ + FragColor = vec4(rgb, 1.0);\ + }"; + +static char *default_glsl_vertex = "\ + varying vec3 gfNormal;\ + varying vec3 gfView;\ + void main(void)\ + {\ + gfView = vec3(gl_ModelViewMatrix * gl_Vertex);\ + gfNormal = normalize(gl_NormalMatrix * gl_Normal);\ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ + gl_TexCoord[0] = gl_MultiTexCoord0;\ + }"; + + + +Bool sdl_compile_shader(u32 shader_id, const char *name, const char *source) +{ + GLint blen = 0; + GLsizei slen = 0; + u32 len; + if (!source || !shader_id) return 0; + len = (u32) strlen(source); + glShaderSource(shader_id, 1, &source, &len); + glCompileShader(shader_id); + + glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH , &blen); + if (blen > 1) { + char* compiler_log = (char*) gf_malloc(blen); +#ifdef CONFIG_DARWIN_GL + glGetInfoLogARB((GLhandleARB) shader_id, blen, &slen, compiler_log); +#else + glGetInfoLogARB(shader_id, blen, &slen, compiler_log); +#endif + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[GLSL] Failed to compile shader %s: %s\n", name, compiler_log)); + gf_free (compiler_log); + return 0; + } + return 1; +} + +void sdl_init(u32 _width, u32 _height, u32 _bpp, u32 stride, Bool use_pbo) +{ + u32 i, flags; + Float hw, hh; + GLint loc; + GF_Matrix mx; + width = _width; + height = _height; + bpp = _bpp; + + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + + flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS | SDL_WINDOW_MAXIMIZED; + if (use_vsync) flags |= SDL_RENDERER_PRESENTVSYNC; + window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); + glctx = SDL_GL_CreateContext(window); + SDL_GL_MakeCurrent(window, glctx); + + render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + + +#if (COPY_TYPE==5) + size = stride*height; +#else + size = width*height; +#endif + if (bpp>8) { + size *= 2; + Bpp = 2; + } + pY = gf_malloc(size*sizeof(u8)); + memset(pY, 0x80, size*sizeof(u8)); + pU = gf_malloc(size/4*sizeof(u8)); + memset(pU, 0, size/4*sizeof(u8)); + pV = gf_malloc(size/4*sizeof(u8)); + memset(pV, 0, size/4*sizeof(u8)); + + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glViewport(0, 0, width, height); + + gf_mx_init(mx); + hw = ((Float)width)/2; + hh = ((Float)height)/2; + gf_mx_ortho(&mx, -hw, hw, -hh, hh, 50, -50); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(mx.m); + + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_NORMALIZE); + glDisable(GL_DEPTH_TEST); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_LIGHTING); + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glDisable(GL_CULL_FACE); + + + GET_GLFUN(glActiveTexture); + GET_GLFUN(glClientActiveTexture); + GET_GLFUN(glCreateProgram); + GET_GLFUN(glDeleteProgram); + GET_GLFUN(glLinkProgram); + GET_GLFUN(glUseProgram); + GET_GLFUN(glCreateShader); + GET_GLFUN(glDeleteShader); + GET_GLFUN(glShaderSource); + GET_GLFUN(glCompileShader); + GET_GLFUN(glAttachShader); + GET_GLFUN(glDetachShader); + GET_GLFUN(glGetShaderiv); + GET_GLFUN(glGetInfoLogARB); + GET_GLFUN(glGetUniformLocation); + GET_GLFUN(glUniform1f); + GET_GLFUN(glUniform1i); + GET_GLFUN(glGenBuffers); + GET_GLFUN(glDeleteBuffers); + GET_GLFUN(glBindBuffer); + GET_GLFUN(glBufferData); + GET_GLFUN(glBufferSubData); + GET_GLFUN(glMapBuffer); + GET_GLFUN(glUnmapBuffer); + + glsl_program = glCreateProgram(); + vertex_shader = glCreateShader(GL_VERTEX_SHADER); + sdl_compile_shader(vertex_shader, "vertex", default_glsl_vertex); + + fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + sdl_compile_shader(fragment_shader, "fragment", glsl_yuv_shader); + + glAttachShader(glsl_program, vertex_shader); + glAttachShader(glsl_program, fragment_shader); + glLinkProgram(glsl_program); + + glGenTextures(3, txid); + for (i=0; i<3; i++) { + + glEnable(texture_type); + glBindTexture(texture_type, txid[i] ); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (bpp>8) { + glPixelTransferi(GL_RED_SCALE, 64); + memory_format=GL_UNSIGNED_SHORT; + } + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (bpp>8) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + glDisable(texture_type); + } + + //sets uniforms: y, u, v textures point to texture slots 0, 1 and 2 + glUseProgram(glsl_program); + for (i=0; i<3; i++) { + const char *txname = (i==0) ? "y_plane" : (i==1) ? "u_plane" : "v_plane"; + loc = glGetUniformLocation(glsl_program, txname); + if (loc == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate texture %s in YUV shader\n", txname)); + continue; + } + glUniform1i(loc, i); + } + loc = glGetUniformLocation(glsl_program, "width"); + if (loc>= 0) { + Float w = (Float) width; + glUniform1f(loc, w); + } + loc = glGetUniformLocation(glsl_program, "height"); + if (loc>= 0) { + Float h = (Float) height; + glUniform1f(loc, h); + } + + glUseProgram(0); + + + if (glMapBuffer==NULL) use_pbo = GF_FALSE; + + + pbo_mode = use_pbo; + first_tx_load = use_pbo ? GF_FALSE : GF_TRUE; + if (use_pbo) { + glGenBuffers(1, &pbo_Y); + glGenBuffers(1, &pbo_U); + glGenBuffers(1, &pbo_V); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_Y); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size, NULL, GL_DYNAMIC_DRAW_ARB); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_U); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size/4, NULL, GL_DYNAMIC_DRAW_ARB); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_V); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size/4, NULL, GL_DYNAMIC_DRAW_ARB); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + } +} + +void sdl_close() +{ + DEL_SHADER(vertex_shader); + DEL_SHADER(fragment_shader); + DEL_PROGRAM(glsl_program ); + + if (pbo_mode && pbo_Y) { + glDeleteBuffers(1, &pbo_Y); + glDeleteBuffers(1, &pbo_U); + glDeleteBuffers(1, &pbo_V); + } + + if (pY) gf_free(pY); + if (pU) gf_free(pU); + if (pV) gf_free(pV); + + if (glctx) SDL_GL_DeleteContext(glctx); + if (render) SDL_DestroyRenderer(render); + if (window) SDL_DestroyWindow(window); +} + +void sdl_draw_quad() +{ + Float w = ((Float)width)/2; + Float h = ((Float)height)/2; + + glBegin(GL_QUADS); + + glVertex3f(w, h, 0); + glTexCoord2f(1, 0); + + glVertex3f(w, -h, 0); + glTexCoord2f(0, 0); + + glVertex3f(-w, -h, 0); + glTexCoord2f(0, 1); + + glVertex3f(-w, h, 0); + glTexCoord2f(1, 1); + + glEnd(); +} + + +void sdl_draw_frame(u8 *pY, u8 *pU, u8 *pV, u32 w, u32 h, u32 bit_depth, u32 stride) +{ + u32 needs_stride = 0; + u64 now, end; + + if (stride != w) { + if (bit_depth==10) { + if (stride != 2*w) { + needs_stride = stride / 2; + } + } else { + needs_stride = stride; + } + } + + glEnable(texture_type); + + now = gf_sys_clock_high_res(); + + + if (first_tx_load) { + glBindTexture(texture_type, txid[0] ); + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride); + glTexImage2D(texture_type, 0, 1, w, h, 0, pixel_format, memory_format, pY); + + glBindTexture(texture_type, txid[1] ); + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride/2); + glTexImage2D(texture_type, 0, 1, w/2, h/2, 0, pixel_format, memory_format, pU); + + glBindTexture(texture_type, txid[2] ); + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride/2); + glTexImage2D(texture_type, 0, 1, w/2, h/2, 0, pixel_format, memory_format, pV); + + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + first_tx_load = GF_FALSE; + } else if (pbo_mode) { + u32 i, linesize, count, p_stride; + u8 *ptr; +#if (COPY_TYPE==2) + u32 *s, *d; + u32 j, c2; +#endif + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_Y); + ptr =(u8 *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); +#if (COPY_TYPE==5) + memcpy(ptr, pY, size); +#elif (COPY_TYPE==3) + memset(ptr, 0x80, size); +#elif (COPY_TYPE==4) +#else + linesize = width*Bpp; + p_stride = stride; + count = h; +#if (COPY_TYPE==2) + c2 = linesize/4; + s = (u32 *)pY; + d = (u32 *)ptr; +#endif + for (i=0; i=GF_ISOM_HEVCTYPE_HEVC_ONLY) { + track = i+1; + break; + } + } + + if (!track) { + gf_isom_close(isom); + sdl_close(); + gf_sys_close(); + return 0; + } + + count = gf_isom_get_sample_count(isom, track); + start = gf_sys_clock_high_res(); + + esd = gf_isom_get_esd(isom, track, 1); + ohevc = libOpenHevcInit(nb_threads, mode); + if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { + libOpenHevcCopyExtraData(ohevc, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength+8); + } + + libOpenHevcSetActiveDecoders(ohevc, 1); + libOpenHevcSetViewLayers(ohevc, 1); + + libOpenHevcStartDecoder(ohevc); + gf_odf_desc_del((GF_Descriptor *)esd); + gf_isom_set_sample_padding(isom, track, 8); + + run=1; + check_prompt=0; + for (i=0; idata, sample->dataLength, sample->DTS+sample->CTS_Offset) ) { + if (no_display) { + OpenHevc_Frame HVCFrame_ptr; + libOpenHevcGetOutput(ohevc, 1, &HVCFrame_ptr); + } else if (use_raw_memory) { + OpenHevc_Frame HVCFrame_ptr; + libOpenHevcGetOutput(ohevc, 1, &HVCFrame_ptr); + + + if (!sdl_is_init && !no_display) { + sdl_init(HVCFrame_ptr.frameInfo.nWidth, HVCFrame_ptr.frameInfo.nHeight, HVCFrame_ptr.frameInfo.nBitDepth, HVCFrame_ptr.frameInfo.nYPitch, use_pbo); + sdl_is_init=1; + start = gf_sys_clock_high_res(); + nb_frames_at_start = i+1; + } + + sdl_draw_frame((u8 *) HVCFrame_ptr.pvY, (u8 *) HVCFrame_ptr.pvU, (u8 *) HVCFrame_ptr.pvV, HVCFrame_ptr.frameInfo.nWidth, HVCFrame_ptr.frameInfo.nHeight, HVCFrame_ptr.frameInfo.nBitDepth, HVCFrame_ptr.frameInfo.nYPitch); + } else { + OpenHevc_Frame_cpy HVCFrame; + memset(&HVCFrame, 0, sizeof(OpenHevc_Frame_cpy) ); + + libOpenHevcGetPictureInfoCpy(ohevc, &HVCFrame.frameInfo); + + if (!sdl_is_init && !no_display) { + sdl_init(HVCFrame.frameInfo.nWidth, HVCFrame.frameInfo.nHeight, HVCFrame.frameInfo.nBitDepth, HVCFrame.frameInfo.nYPitch, use_pbo); + sdl_is_init=1; + start = gf_sys_clock_high_res(); + nb_frames_at_start = i+1; + } + + HVCFrame.pvY = (void*) pY; + HVCFrame.pvU = (void*) pU; + HVCFrame.pvV = (void*) pV; + + libOpenHevcGetOutputCpy(ohevc, 1, &HVCFrame); + + sdl_draw_frame(pY, pU, pV, HVCFrame.frameInfo.nWidth, HVCFrame.frameInfo.nHeight, HVCFrame.frameInfo.nBitDepth, HVCFrame.frameInfo.nYPitch); + } + } + + gf_isom_sample_del(&sample); + + now = gf_sys_clock_high_res(); + fprintf(stderr, "%d %% %d frames in %d ms - FPS %03.2f - push time "LLD" ms - draw "LLD" ms\r", 100*(i+1-nb_frames_at_start)/count, i+1-nb_frames_at_start, (now-start)/1000, 1000000.0 * (i+1-nb_frames_at_start) / (now-start), gl_upload_time / gl_nb_frames/1000 , (gl_draw_time - gl_upload_time) / gl_nb_frames/1000 ); + } else { + gf_sleep(10); + i--; + } + check_prompt++; + if (check_prompt==50) { + if (gf_prompt_has_input()) { + switch (gf_prompt_get_char()) { + case 'q': + run = 0; + break; + case 'm': + use_raw_memory = !use_raw_memory; + break; + case 'p': + if (paused) { + paused=0; + start += gf_sys_clock_high_res()-pause_time; + } else { + paused = 1; + pause_time=gf_sys_clock_high_res(); + } + break; + case 'r': + start = gf_sys_clock_high_res(); + nb_frames_at_start = i+1; + gl_upload_time = gl_draw_time = 0; + gl_nb_frames=1; + break; + + } + } + check_prompt=0; + } + } + now = gf_sys_clock_high_res(); + fprintf(stderr, "\nDecoded %d frames in %d ms - FPS %g\n", i+1, (now-start)/1000, 1000000.0 * (i+1) / (now-start) ); + + libOpenHevcClose(ohevc); + gf_isom_close(isom); + + if (!no_display) + sdl_close(); + + gf_sys_close(); + return 1; +} + diff --git a/applications/testapps/largefile/largefile.dsp b/applications/testapps/largefile/largefile.dsp new file mode 100644 index 0000000..3a568ad --- /dev/null +++ b/applications/testapps/largefile/largefile.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="largefile" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=largefile - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "largefile.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "largefile.mak" CFG="largefile - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "largefile - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "largefile - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "largefile - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 winmm.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "largefile - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "largefile - Win32 Release" +# Name "largefile - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/largefile/largefile.dsw b/applications/testapps/largefile/largefile.dsw new file mode 100644 index 0000000..d1ebaae --- /dev/null +++ b/applications/testapps/largefile/largefile.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "largefile"=.\largefile.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libgpac + End Project Dependency +}}} + +############################################################################### + +Project: "libgpac"=..\..\..\build\msvc6\libgpac.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/testapps/largefile/main.c b/applications/testapps/largefile/main.c new file mode 100644 index 0000000..289d878 --- /dev/null +++ b/applications/testapps/largefile/main.c @@ -0,0 +1,85 @@ +#include + +void PrintUsage() +{ + fprintf(stdout, + "Usage: largefile [options]\n" + "Option is one of:\n" + "-flat test file writing in flat mode (moov at end)\n" + "-inter test file writing in interleaved mode (moov at begin)\n" + "-size size specifies target media size in GB. Default is 5.0 GB\n" + "" + ); +} +#define TEST_FILE_NAME "largefile.mp4" + +int main(int argc, char **argv) +{ + GF_ISOFile *movie; + GF_ESD *esd; + GF_Err e; + Double gb_size = 5.0; + u8 store_mode; + u32 track, di, i, nb_samp; + GF_ISOSample *samp; + + store_mode = GF_ISOM_OPEN_WRITE; + for (i=1; idecoderConfig->streamType = 4; + gf_isom_new_mpeg4_description(movie, track, esd, NULL, NULL, &di); + + samp = gf_isom_sample_new(); + samp->dataLength = 1024*1024; + samp->data = gf_malloc(sizeof(char)*samp->dataLength); + memset(samp->data, 0, sizeof(char)*samp->dataLength); + + for (i=0; iDTS % 25) samp->IsRAP = 0; + else samp->IsRAP = 1; + e = gf_isom_add_sample(movie, track, di, samp); + samp->DTS += 1; + + fprintf(stdout, "Writing sample %d / %d \r", i+1, nb_samp); + if (e) break; + } + gf_isom_sample_del(&samp); + + if (e) { + fprintf(stdout, "\nError writing sample %d\n", i); + gf_isom_delete(movie); + return 1; + } + + fprintf(stdout, "\nDone writing samples\n"); + e = gf_isom_close(movie); + if (e) { + fprintf(stdout, "Error writing file\n"); + return 1; + } + return 0; +} + + diff --git a/applications/testapps/loadcompare/LoadCompare.dsp b/applications/testapps/loadcompare/LoadCompare.dsp new file mode 100644 index 0000000..033efac --- /dev/null +++ b/applications/testapps/loadcompare/LoadCompare.dsp @@ -0,0 +1,112 @@ +# Microsoft Developer Studio Project File - Name="LoadCompare" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=LoadCompare - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LoadCompare.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LoadCompare.mak" CFG="LoadCompare - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LoadCompare - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "LoadCompare - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LoadCompare - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "LoadCompare___Win32_Release" +# PROP BASE Intermediate_Dir "LoadCompare___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "obj/loadcompare_rel" +# PROP Intermediate_Dir "obj/loadcompare_rel" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /I "../../../extra_lib/include/zlib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 zlib.lib winmm.lib libxml2.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/LoadCompare.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "LoadCompare - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "LoadCompare___Win32_Debug" +# PROP BASE Intermediate_Dir "LoadCompare___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "obj/loadcompare_deb" +# PROP Intermediate_Dir "obj/loadcompare_deb" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /I "../../../extra_lib/include/zlib" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 zlib.lib winmm.lib libxml2.lib /nologo /subsystem:console /pdb:"obj/loadcompare_deb//LoadCompare.pdb" /debug /machine:I386 /out:"../../../bin/w32_deb/LoadCompare.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "LoadCompare - Win32 Release" +# Name "LoadCompare - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\loadcompare.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\modules\svg_loader\lsr_parser.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\modules\svg_loader\svg_parser.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/loadcompare/Makefile b/applications/testapps/loadcompare/Makefile new file mode 100644 index 0000000..8dc31d1 --- /dev/null +++ b/applications/testapps/loadcompare/Makefile @@ -0,0 +1,55 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/testapps/loadcompare + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +CFLAGS+=$(XML2_CFLAGS) + +#common obj +OBJS= loadcompare.o ../../../modules/svg_loader/svg_parser.o ../../../modules/svg_loader/lsr_parser.o + +LINKFLAGS=-L../../../bin/gcc +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=LoadCompare$(EXE) +#LINKFLAGS+=-lgpac_static -lz $(EXTRALIBS) +LINKFLAGS+=-lgpac +else +EXT= +PROG=LoadCompare +#LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS) -lz +LINKFLAGS+=-lgpac -lz $(XML2_LIBS) +endif + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/testapps/loadcompare/loadcompare.c b/applications/testapps/loadcompare/loadcompare.c new file mode 100644 index 0000000..54e2dec --- /dev/null +++ b/applications/testapps/loadcompare/loadcompare.c @@ -0,0 +1,698 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril Concolato + * Copyright (c) Telecom ParisTech 2006-2012 + * All rights reserved + * + * This file is part of GPAC / load&compare application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include +#include + +enum { + SVG = 0, + XMT = 1, +}; + +typedef struct { + char filename[100]; + u32 size; + u32 gpacxml_loadtime; + u32 libxml_loadtime; + u32 gz_size; + u32 gpacxml_gz_loadtime; + u32 libxml_gz_loadtime; + u32 track_size; + u32 track_loadtime; + u32 decoded_size; + u32 decoded_loadtime; +} LoadData; + +typedef struct { + FILE *out; + u32 type; + u32 nbloads; + u32 verbose; + Bool regenerate; + Bool spread_repeat; + u32 repeat_index; + GF_List *data; +} GF_LoadCompare; + +GF_Err load_mp4(GF_LoadCompare *lc, GF_ISOFile *mp4, u32 *loadtime) +{ + GF_Err e = GF_OK; + GF_SceneLoader load; + GF_SceneGraph *sg; + u32 i, starttime, endtime; + u32 nb; + if (lc->spread_repeat) nb = 1; + else nb = lc->nbloads ; + + *loadtime = 0; + for (i = 0; i< nb; i++) { + memset(&load, 0, sizeof(GF_SceneLoader)); + sg = gf_sg_new(); + load.ctx = gf_sm_new(sg); + + load.isom = mp4; + starttime = gf_sys_clock(); + + e = gf_sm_load_init(&load); + if (e) { + fprintf(stderr, "Error loading MP4 file\n"); + } else { + e = gf_sm_load_run(&load); + if (e) { + fprintf(stderr, "Error loading MP4 file\n"); + } else { + endtime = gf_sys_clock(); + *loadtime += endtime-starttime; + } + gf_sm_load_done(&load); + } + gf_sm_del(load.ctx); + gf_sg_del(sg); + } + return e; +} + +void load_progress(void *cbk, u32 done, u32 total) { + fprintf(stdout, "%d/%d\r", done, total); +} + +GF_Err gpacctx_load_file(GF_LoadCompare *lc, char *item_path, u32 *loadtime) +{ + GF_Err e = GF_OK; + GF_SceneLoader load; + GF_SceneGraph *sg; + u32 i, starttime, endtime; + + u32 nb; + if (lc->spread_repeat) nb = 1; + else nb = lc->nbloads ; + + *loadtime = 0; + + for (i = 0; idataLength; + gf_isom_sample_del(&samp); + } + return e; +} + +GF_Err encode_laser(GF_LoadCompare *lc, char *item_path, GF_ISOFile *mp4, GF_SMEncodeOptions *opts) +{ + GF_Err e = GF_OK; + GF_SceneLoader load; + GF_SceneManager *ctx; + GF_SceneGraph *sg; + GF_StatManager *statsman = NULL; + + memset(&load, 0, sizeof(GF_SceneLoader)); + sg = gf_sg_new(); + ctx = gf_sm_new(sg); + load.ctx = ctx; + load.fileName = item_path; + + e = gf_sm_load_init(&load); + if (e) { + fprintf(stderr, "Error loading file %s\n", item_path); + } else { + e = gf_sm_load_run(&load); + if (e) { + fprintf(stderr, "Error loading file %s\n", item_path); + } else { + if (opts->auto_qant) { + if (lc->verbose) fprintf(stdout, "Analysing Scene for Automatic Quantization\n"); + statsman = gf_sm_stats_new(); + e = gf_sm_stats_for_scene(statsman, ctx); + if (!e) { + GF_SceneStatistics *stats = gf_sm_stats_get(statsman); + if (opts->resolution > (s32)stats->frac_res_2d) { + if (lc->verbose) fprintf(stdout, " Given resolution %d is (unnecessarily) too high, using %d instead.\n", opts->resolution, stats->frac_res_2d); + opts->resolution = stats->frac_res_2d; + } else if (stats->int_res_2d + opts->resolution <= 0) { + if (lc->verbose) fprintf(stdout, " Given resolution %d is too low, using %d instead.\n", opts->resolution, stats->int_res_2d - 1); + opts->resolution = 1 - stats->int_res_2d; + } + opts->coord_bits = stats->int_res_2d + opts->resolution; + if (lc->verbose) fprintf(stdout, " Coordinates & Lengths encoded using "); + if (opts->resolution < 0) { + if (lc->verbose) fprintf(stdout, "only the %d most significant bits (of %d).\n", opts->coord_bits, stats->int_res_2d); + } else { + if (lc->verbose) fprintf(stdout, "a %d.%d representation\n", stats->int_res_2d, opts->resolution); + } + + if (lc->verbose) fprintf(stdout, " Matrix Scale & Skew Coefficients "); + if (opts->coord_bits < stats->scale_int_res_2d) { + opts->scale_bits = stats->scale_int_res_2d - opts->coord_bits; + if (lc->verbose) fprintf(stdout, "encoded using a %d.8 representation\n", stats->scale_int_res_2d); + } else { + opts->scale_bits = 0; + if (lc->verbose) fprintf(stdout, "not encoded.\n"); + } + } + gf_sm_stats_del(statsman); + } + + e = gf_sm_encode_to_file(ctx, mp4, opts); + if (e) { + fprintf(stderr, "Error while encoding mp4 file\n"); + } else { + e = gf_isom_set_brand_info(mp4, GF_ISOM_BRAND_MP42, 1); + if (!e) e = gf_isom_modify_alternate_brand(mp4, GF_ISOM_BRAND_ISOM, 1); + } + + gf_sm_load_done(&load); + } + } + gf_sm_del(ctx); + gf_sg_del(sg); + + return e; +} + +GF_Err create_laser_mp4(GF_LoadCompare *lc, char *item_name, char *item_path, u32 *size) +{ + char mp4_path[100], *ext; + GF_Err e = GF_OK; + GF_ISOFile *mp4; + + *size = 0; + + strcpy(mp4_path, item_name); + ext = strrchr(mp4_path, '.'); + strcpy(ext, ".mp4"); + mp4 = gf_isom_open(mp4_path, GF_ISOM_WRITE_EDIT, NULL); + if (!mp4) { + if (lc->verbose) fprintf(stdout, "Could not open file %s for writing\n", mp4_path); + e = GF_IO_ERR; + } else { + GF_SMEncodeOptions opts; + memset(&opts, 0, sizeof(GF_SMEncodeOptions)); + opts.auto_qant = 1; + opts.resolution = 8; + e = encode_laser(lc, item_path, mp4, &opts); + if (e) { + if (lc->verbose) fprintf(stdout, "Could not encode MP4 file from %s\n", item_path); + gf_isom_delete(mp4); + } else { + gf_isom_close(mp4); + + mp4 = gf_isom_open(mp4_path, GF_ISOM_OPEN_READ, NULL); + if (!mp4) { + if (lc->verbose) fprintf(stdout, "Could not open file %s for reading\n", mp4_path); + e = GF_IO_ERR; + } else { + e = get_laser_track_size(mp4, size); + if (e) { + if (lc->verbose) fprintf(stdout, "Could not get MP4 file size\n"); + } + gf_isom_close(mp4); + } + } + } + return e; +} + + +GF_Err get_mp4_loadtime(GF_LoadCompare *lc, char *item_name, char *item_path, u32 *loadtime) +{ + char mp4_path[100], *ext; + GF_Err e = GF_OK; + GF_ISOFile *mp4; + + *loadtime = 0; + + strcpy(mp4_path, item_name); + ext = strrchr(mp4_path, '.'); + strcpy(ext, ".mp4"); + mp4 = gf_isom_open(mp4_path, GF_ISOM_OPEN_READ, NULL); + if (!mp4) { + if (lc->verbose) fprintf(stdout, "Could not open file %s for reading\n", mp4_path); + e = GF_IO_ERR; + } else { + e = load_mp4(lc, mp4, loadtime); + if (e) { + if (lc->verbose) fprintf(stdout, "Could not get MP4 file load time\n"); + } + } + gf_isom_close(mp4); + return e; +} + +GF_Err decode_svg(GF_LoadCompare *lc, char *item_name, char *item_path, char *svg_out_path) +{ + GF_SceneManager *ctx; + GF_SceneGraph *sg; + GF_SceneLoader load; + GF_ISOFile *mp4; + GF_Err e = GF_OK; + char mp4_path[256]; + char *ext; + + strcpy(mp4_path, item_name); + ext = strrchr(mp4_path, '.'); + strcpy(ext, ".mp4"); + mp4 = gf_isom_open(mp4_path, GF_ISOM_OPEN_READ, NULL); + if (!mp4) { + if (lc->verbose) fprintf(stdout, "Could not open file %s\n", mp4_path); + e = GF_IO_ERR; + } else { + sg = gf_sg_new(); + ctx = gf_sm_new(sg); + memset(&load, 0, sizeof(GF_SceneLoader)); + load.isom = mp4; + load.ctx = ctx; + e = gf_sm_load_init(&load); + if (e) { + fprintf(stderr, "Error loading MP4 file\n"); + } else { + e = gf_sm_load_run(&load); + if (e) { + fprintf(stderr, "Error loading MP4 file\n"); + } else { + gf_sm_load_done(&load); + + ext = strrchr(svg_out_path, '.'); + ext[0] = 0; + e = gf_sm_dump(ctx, svg_out_path, GF_SM_DUMP_SVG); + if (e) { + fprintf(stderr, "Error dumping SVG from MP4 file\n"); + } + } + } + gf_sm_del(ctx); + gf_sg_del(sg); + gf_isom_close(mp4); + } + return e; +} + +GF_Err libxml_load_svg(GF_LoadCompare *lc, char *item_path, u32 *loadtime) +{ + GF_Err e = GF_OK; + GF_SceneGraph *sg; + u32 i, starttime, endtime; + void *p; + + u32 nb; + if (lc->spread_repeat) nb = 1; + else nb = lc->nbloads ; + + *loadtime = 0; + + for (i = 0; iverbose) fprintf(stdout, "LibXML single parsing: %d\n", endtime-starttime); + *loadtime += endtime-starttime; + + gf_sg_del(sg); + } + return e; +} + +GF_Err get_size(GF_LoadCompare *lc, char *item_name, char *item_path, u32 *size) +{ + GF_Err e = GF_OK; + FILE *file = NULL; + + *size = 0; + + file = gf_fopen(item_path, "rt"); + if (!file) { + if (lc->verbose) fprintf(stdout, "Could not open file %s\n", item_path); + e = GF_IO_ERR; + } else { + fseek(file, 0, SEEK_END); + *size = (u32)ftell(file); + gf_fclose(file); + if (*size == 0) { + if (lc->verbose) fprintf(stdout, "File %s has a size of 0\n", item_path); + e = GF_IO_ERR; + } + } + return e; +} + +GF_Err get_decoded_svg_loadtime_and_size(GF_LoadCompare *lc, char *item_name, char *item_path, u32 *loadtime, u32 *size) +{ + GF_Err e = GF_OK; + char svg_out_name[256]; + char *ext; + + strcpy(svg_out_name, item_name); + ext = strrchr(svg_out_name, '.'); + strcpy(ext, "_out.svg"); + + *size = 0; + *loadtime = 0; + + e = decode_svg(lc, item_name, item_path, svg_out_name); + if (!e) { + e = get_size(lc, svg_out_name, svg_out_name, size); + if (e) { + return e; + } + e = gpacctx_load_file(lc, svg_out_name, loadtime); + } + return e; +} + +GF_Err create_gz_file(GF_LoadCompare *lc, char *item_name, char *item_path, u32 *size) +{ + char buffer[100]; + char gz_path[256]; + GF_Err e = GF_OK; + FILE *file = NULL; + void *gz = NULL; + u32 read; + + *size = 0; + + strcpy(gz_path, item_name); + strcat(gz_path, "z"); + gz = gzopen(gz_path, "wb"); + file = gf_fopen(item_path, "rt"); + + if (!gz || !file) { + if (lc->verbose) fprintf(stdout, "Could not open file %s or %s\n", item_path, gz_path); + e = GF_IO_ERR; + } else { + while ((read = fread(buffer, 1, 100, file))) gzwrite(gz, buffer, read); + gf_fclose(file); + gzclose(gz); + file = gf_fopen(gz_path, "rb"); + fseek(file, 0, SEEK_END); + *size = (u32)ftell(file); + gf_fclose(file); + if (*size == 0) { + if (lc->verbose) fprintf(stdout, "File %s has a size of 0\n", gz_path); + e = GF_IO_ERR; + } + } + return e; +} + +GF_Err get_gz_loadtime(GF_LoadCompare *lc, char *item_name, char *item_path, u32 *loadtime, Bool useLibXML) +{ + char gz_path[256]; + GF_Err e = GF_OK; + *loadtime = 0; + + strcpy(gz_path, item_name); + strcat(gz_path, "z"); + + if (useLibXML) { + e = libxml_load_svg(lc, gz_path, loadtime); + } else { + e = gpacctx_load_file(lc, gz_path, loadtime); + } + return e; +} + +void print_load_data(GF_LoadCompare *lc, LoadData *ld) +{ + if (lc->verbose) fprintf(stdout, "Processing %s\n", ld->filename); + fprintf(lc->out, "%s\t", ld->filename); + + if (lc->verbose) fprintf(stdout, "File Size %d\n", ld->size); + fprintf(lc->out, "%d\t", ld->size); + + if (lc->verbose) fprintf(stdout, "GPAC XML Load Time %d\n", ld->gpacxml_loadtime); + fprintf(lc->out, "%d\t", ld->gpacxml_loadtime); + + if (lc->verbose) fprintf(stdout, "LibXML Load Time %d \n", ld->libxml_loadtime); + fprintf(lc->out, "%d\t", ld->libxml_loadtime); + + if (lc->verbose) fprintf(stdout, "GZ Size %d\n", ld->gz_size); + fprintf(lc->out, "%d\t", ld->gz_size); + + if (lc->verbose) fprintf(stdout, "GZ Load Time %d\n", ld->gpacxml_gz_loadtime); + fprintf(lc->out, "%d\t", ld->gpacxml_gz_loadtime); + + if (lc->verbose) fprintf(stdout, "LibXML GZ Load Time %d\n", ld->libxml_gz_loadtime); + fprintf(lc->out, "%d\t", ld->libxml_gz_loadtime); + + if (lc->verbose) fprintf(stdout, "MP4 Track Size %d\n", ld->track_size); + fprintf(lc->out, "%d\t", ld->track_size); + + if (lc->verbose) fprintf(stdout, "MP4 Track Load Time %d\n", ld->track_loadtime); + fprintf(lc->out, "%d\t", ld->track_loadtime); + + if (lc->verbose) fprintf(stdout, "Decoded Size %d\n", ld->decoded_size); + fprintf(lc->out, "%d\t", ld->decoded_size); + + if (lc->verbose) fprintf(stdout, "Decoded Load Time %d \n", ld->decoded_loadtime); + fprintf(lc->out, "%d\t", ld->decoded_loadtime); + + if (lc->verbose) fprintf(stdout, "Done %s\n", ld->filename); + fprintf(lc->out, "\n"); + fflush(lc->out); +} + +Bool loadcompare_one(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) +{ + GF_Err e; + GF_LoadCompare *lc = cbck; + u32 loadtime; + LoadData *ld; + + if (lc->repeat_index == 0) { + GF_SAFEALLOC(ld, sizeof(LoadData)); + gf_list_add(lc->data, ld); + strcpy(ld->filename, item_name); + + e = get_size(lc, item_name, item_path, &ld->size); + if (e) return 1; + + e = create_gz_file(lc, item_name, item_path, &ld->gz_size); + if (e) return 1; + + e = create_laser_mp4(lc, item_name, item_path, &ld->track_size); + if (e) return 1; + + } else { + LoadData *tmp; + u32 pos = 0; + ld = NULL; + while (tmp = gf_list_enum(lc->data, &pos)) { + if (!strcmp(tmp->filename, item_name)) { + ld = tmp; + break; + } + } + if (ld == NULL) return 1; + } + + + if (lc->type == SVG) { + /* GPAC XML loader */ + e = gpacctx_load_file(lc, item_path, &loadtime); + if (e) return 1; + ld->gpacxml_loadtime += loadtime; + + e = get_gz_loadtime(lc, item_name, item_path, &loadtime, 0); + if (e) return 1; + ld->gpacxml_gz_loadtime += loadtime; + + /* LibXML and LibXML GZ loadings */ + e = libxml_load_svg(lc, item_path, &loadtime); + if (e) return 1; + ld->libxml_loadtime += loadtime; + + e = get_gz_loadtime(lc, item_name, item_path, &loadtime, 1); + if (e) return 1; + ld->libxml_gz_loadtime += loadtime; + + /* MP4 Loading */ + e = get_mp4_loadtime(lc, item_name, item_path, &loadtime); + if (e) return 1; + ld->track_loadtime += loadtime; + + /* e = get_decoded_svg_loadtime_and_size(lc, item_name, item_path, &loadtime, &ld->decoded_size); + if (e) return 1; + ld->decoded_loadtime += loadtime;*/ + + } else if (lc->type == XMT) { + e = gpacctx_load_file(lc, item_path, &loadtime); + if (e) return 1; + ld->gpacxml_loadtime += loadtime; + } + + if (!lc->spread_repeat) { + print_load_data(lc, ld); + gf_free(ld); + } + return 0; +} + +void usage() +{ + fprintf(stdout, "Compare LASeR and SVG encoding size and loading time\n"); + fprintf(stdout, "usage: (-out output_result) (-single input.svg | -dir dir) (-nloads X) (-verbose X)\n"); + fprintf(stdout, "defaults are: stdout, dir=. and X = 1"); +} + +int main(int argc, char **argv) +{ + u32 i; + char *arg; + GF_LoadCompare lc; + Bool single = 0; + char *out = NULL; + char in[256] = "."; + + fprintf(stdout, "LASeR and SVG Comparison tool\n"); + + memset(&lc, 0, sizeof(GF_LoadCompare)); + lc.nbloads = 1; + lc.out = stdout; + + for (i = 1; i < (u32) argc ; i++) { + arg = argv[i]; + if (!stricmp(arg, "-out")) { + out = argv[i+1]; + i++; + } else if (!stricmp(arg, "-single")) { + single = 1; + strcpy(in, argv[i+1]); + i++; + } else if (!stricmp(arg, "-dir")) { + strcpy(in, argv[i+1]); + i++; + } else if (!stricmp(arg, "-nloads")) { + lc.nbloads = (u32)atoi(argv[i+1]); + i++; + } else if (!stricmp(arg, "-regenerate")) { + lc.regenerate = 1; + } else if (!stricmp(arg, "-xmt")) { + lc.type = XMT; + } else if (!stricmp(arg, "-svg")) { + lc.type = SVG; + } else if (!stricmp(arg, "-spread_repeat")) { + lc.spread_repeat = 1; + } else if (!stricmp(arg, "-verbose")) { + lc.verbose = (u32)atoi(argv[i+1]); + i++; + } else { + usage(); + return -1; + } + } + + gf_sys_init(); + if (out) lc.out = gf_fopen(out, "wt"); + if (!lc.out) { + fprintf(stderr, "Cannot open output file %s\n", out); + return -1; + } + + if (lc.type == SVG) { + fprintf(lc.out,"File Name\tSVG Size\tSVG Load Time\tLibXML Load Time\tSVGZ Size\tSVGZ Load Time\tLibXML GZ Load Time\tMP4 Size\tMP4 Load Time\tDecoded SVG Size\tDecoded SVG Load Time\n"); + } else if (lc.type == XMT) { + fprintf(lc.out,"File Name\tXMT Size\tXMT Load Time\tBT Size\tBT Load Time\n"); + } + + lc.data = gf_list_new(); + + if (single) { + LoadData *ld; + char *tmp = strrchr(in, GF_PATH_SEPARATOR); + loadcompare_one(&lc, tmp+1, in); + ld = gf_list_get(lc.data, 0); + print_load_data(&lc, ld); + gf_free(ld); + } else { + if (lc.spread_repeat) { + for (lc.repeat_index = 0; lc.repeat_index < lc.nbloads; lc.repeat_index ++) { + if (lc.verbose) fprintf(stdout, "Loop %d\n", lc.repeat_index); + if (lc.type == SVG) { + gf_enum_directory(in, 0, loadcompare_one, &lc, "svg"); + } else if (lc.type == XMT) { + gf_enum_directory(in, 0, loadcompare_one, &lc, "xmt"); + } + } + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/testapps/mpedemux/Makefile b/applications/testapps/mpedemux/Makefile new file mode 100644 index 0000000..7f3c21b --- /dev/null +++ b/applications/testapps/mpedemux/Makefile @@ -0,0 +1,65 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/test_apps/mpedemux + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#file format is read-only +ifeq ($(GPACREADONLY), yes) +CFLAGS+= -DGPAC_READ_ONLY +endif + +ifeq ($(DISABLE_SVG), yes) +CFLAGS+=-DGPAC_DISABLE_SVG +endif + +#common obj +OBJS= main.o + +LINKFLAGS=-L../../../bin/gcc +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=mpedemux$(EXE) +LINKFLAGS+=-lgpac_static -lz $(EXTRALIBS) +#LINKFLAGS+=-lgpac +else +EXT= +PROG=mpedemux +LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS) -lz +#LINKFLAGS+=-lgpac -lz +endif + + +SRCS := $(OBJS:.o=.c) + +all: LIBGPAC $(PROG) + +LIBGPAC: + $(MAKE) -C ../../../src + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/testapps/mpedemux/main.c b/applications/testapps/mpedemux/main.c new file mode 100644 index 0000000..a3389d3 --- /dev/null +++ b/applications/testapps/mpedemux/main.c @@ -0,0 +1,103 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2007-2012 + * All rights reserved + * + * This file is part of GPAC / mpedemux application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include + +typedef struct +{ + FILE *ts_file; + GF_M2TS_Demuxer *ts_demux; +} MPEDemux; + + +static void mpedemux_on_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) +{ + MPEDemux *mpedemux= (MPEDemux *) ts->user; + switch (evt_type) { + case GF_M2TS_EVT_PAT_FOUND: + /* called when the first PAT is fully parsed */ + break; + case GF_M2TS_EVT_SDT_FOUND: + /* called when the first SDT is fully parsed */ + break; + case GF_M2TS_EVT_PMT_FOUND: + /* called when a first PMT is fully parsed */ + break; + case GF_M2TS_EVT_INT_FOUND: + /* called when a first INT is fully parsed */ + /* TODO: create socket for each target in the IP platform */ + break; + case GF_M2TS_EVT_PAT_UPDATE: + case GF_M2TS_EVT_PMT_UPDATE: + case GF_M2TS_EVT_SDT_UPDATE: + /* called when a new version of the table is parsed */ + break; + case GF_M2TS_EVT_PES_PCK: + /* called when a PES packet is parsed */ + break; + case GF_M2TS_EVT_SL_PCK: + /* called when an MPEG-4 SL-packet is parsed */ + break; + case GF_M2TS_EVT_IP_DATAGRAM: + /* called when an IP packet is parsed + TODO: send this packet on the right socket */ + break; + } +} + +static void usage() +{ + fprintf(stdout, "mpedemux input.ts\n"); +} + +int main(int argc, char **argv) +{ + u8 data[188]; + u32 size; + MPEDemux *mpedemux; + + if (argc < 2) { + usage(); + return GF_OK; + } + + GF_SAFEALLOC(mpedemux, MPEDemux); + mpedemux->ts_demux = gf_m2ts_demux_new(); + mpedemux->ts_demux->on_event = mpedemux_on_event; + mpedemux->ts_demux->user = mpedemux; + + mpedemux->ts_file = gf_fopen(argv[1], "rb"); + + while (1) { + /*read chunks by chunks*/ + size = fread(data, 1, 188, mpedemux->ts_file); + if (!size) break; + /*process chunk*/ + gf_m2ts_process_data(mpedemux->ts_demux, data, size); + } + + gf_m2ts_demux_del(mpedemux->ts_demux); + gf_free(mpedemux); + return GF_OK; +} diff --git a/applications/testapps/mpedemux/mpedemux.dsp b/applications/testapps/mpedemux/mpedemux.dsp new file mode 100644 index 0000000..b4f3317 --- /dev/null +++ b/applications/testapps/mpedemux/mpedemux.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="mpedemux" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mpedemux - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mpedemux.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mpedemux.mak" CFG="mpedemux - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mpedemux - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mpedemux - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mpedemux - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 zlib.lib winmm.lib ws2_32.lib js32.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/mpedemux.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "mpedemux - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 zlib.lib winmm.lib ws2_32.lib js32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/mpedemux.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "mpedemux - Win32 Release" +# Name "mpedemux - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Target +# End Project diff --git a/applications/testapps/mpeg2ts/main.c b/applications/testapps/mpeg2ts/main.c new file mode 100644 index 0000000..a9f3a84 --- /dev/null +++ b/applications/testapps/mpeg2ts/main.c @@ -0,0 +1,88 @@ +#include + +u32 dump_pid = 130; +FILE *dest = NULL; +Bool has_seen_pat = 0; + +void on_m2ts_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) +{ + GF_M2TS_PES_PCK *pck; + switch (evt_type) { + case GF_M2TS_EVT_PAT_FOUND: + fprintf(stdout, "Service connected (PAT found)\n"); + break; + case GF_M2TS_EVT_PAT_REPEAT: + has_seen_pat = 1; + break; + case GF_M2TS_EVT_PAT_UPDATE: + fprintf(stdout, "Service connected (PAT found)\n"); + break; + case GF_M2TS_EVT_PMT_FOUND: + fprintf(stdout, "Program list found - %d streams\n", gf_list_count( ((GF_M2TS_Program*)par)->streams) ); + break; + case GF_M2TS_EVT_PMT_UPDATE: + fprintf(stdout, "Program list updated - %d streams\n", gf_list_count( ((GF_M2TS_Program*)par)->streams) ); + break; + case GF_M2TS_EVT_SDT_FOUND: + fprintf(stdout, "Program Description found - %d desc\n", gf_list_count(ts->SDTs) ); + break; + case GF_M2TS_EVT_SDT_UPDATE: + fprintf(stdout, "Program Description updated - %d desc\n", gf_list_count(ts->SDTs) ); + break; + case GF_M2TS_EVT_PES_PCK: + pck = par; + if (dest && (dump_pid == pck->stream->pid)) { + gf_fwrite(pck->data, pck->data_len, 1, dest); + } + + //fprintf(stdout, "PES(%d): DTS "LLD" PTS" LLD" RAP %d size %d\n", pck->stream->pid, pck->DTS, pck->PTS, pck->rap, pck->data_len); + break; + } +} + +int main(int argc, char **argv) +{ + char data[188]; + u32 size, fsize, fdone; + GF_M2TS_Demuxer *ts; + + FILE *src = gf_fopen(argv[1], "rb"); + ts = gf_m2ts_demux_new(); + ts->on_event = on_m2ts_event; + + fseek(src, 0, SEEK_END); + fsize = ftell(src); + fseek(src, 0, SEEK_SET); + fdone = 0; + + while (!feof(src)) { + size = fread(data, 1, 188, src); + if (size<188) break; + + gf_m2ts_process_data(ts, data, size); + if (has_seen_pat) break; + } + + dest = gf_fopen("pes.mp3", "wb"); + gf_m2ts_reset_parsers(ts); + gf_fseek(src, 0, SEEK_SET); + fdone = 0; + while (!feof(src)) { + size = fread(data, 1, 188, src); + if (size<188) break; + + gf_m2ts_process_data(ts, data, size); + + fdone += size; + gf_set_progress("MPEG-2 TS Parsing", fdone, fsize); + } + gf_set_progress("MPEG-2 TS Parsing", fsize, fsize); + + gf_fclose(src); + gf_m2ts_demux_del(ts); + if (dest) gf_fclose(dest); + return 0; +} + + + diff --git a/applications/testapps/mpeg2ts/mpeg2ts.dsp b/applications/testapps/mpeg2ts/mpeg2ts.dsp new file mode 100644 index 0000000..37052e4 --- /dev/null +++ b/applications/testapps/mpeg2ts/mpeg2ts.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="mpeg2ts" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mpeg2ts - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mpeg2ts.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mpeg2ts.mak" CFG="mpeg2ts - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mpeg2ts - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mpeg2ts - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mpeg2ts - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "mpeg2ts - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 zlib.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mpeg2ts - Win32 Release" +# Name "mpeg2ts - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/segmp4demux/Makefile b/applications/testapps/segmp4demux/Makefile new file mode 100644 index 0000000..964c077 --- /dev/null +++ b/applications/testapps/segmp4demux/Makefile @@ -0,0 +1,50 @@ +include ../../../config.mak + +vpath %.c $(SRC_PATH)/applications/testapps/segmp4demux + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o + +LINKFLAGS=-L../../../bin/gcc +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=segmp4demux$(EXE) +else +EXT= +PROG=segmp4demux +endif +LINKFLAGS+=-lgpac + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/testapps/segmp4demux/build.sh b/applications/testapps/segmp4demux/build.sh new file mode 100644 index 0000000..d1dd330 --- /dev/null +++ b/applications/testapps/segmp4demux/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_file.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB diff --git a/applications/testapps/segmp4demux/main.c b/applications/testapps/segmp4demux/main.c new file mode 100644 index 0000000..dd220fb --- /dev/null +++ b/applications/testapps/segmp4demux/main.c @@ -0,0 +1,139 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Romain Bouqueau - Cyril Concolato + * Copyright (c) Romain Bouqueau 2013- + * Copyright (c) Telecom ParisTech 2013- + * All rights reserved + * + * This file is part of GPAC / sample MP4 demultiplexing application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +static void process_samples_from_track(GF_ISOFile *movie, u32 track_id, u32 *sample_index) +{ + u32 track_number; + u32 sample_count; + /* Error indicator */ + GF_Err e; + /* Number of bytes required to finish the current ISO Box reading */ + u64 missing_bytes; + + track_number = gf_isom_get_track_by_id(movie, track_id); + if (track_number == 0) { + fprintf(stdout, "Could not find track ID=%u. Ignore segment.\n", track_id); + return; + } + + sample_count = gf_isom_get_sample_count(movie, track_number); + while (*sample_index <= sample_count) { + GF_ISOSample *iso_sample; + u32 sample_description_index; + + iso_sample = gf_isom_get_sample(movie, track_number, *sample_index, &sample_description_index); + if (iso_sample) { + fprintf(stdout, "Found sample #%5d/%5d of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\n", *sample_index, sample_count, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset); + (*sample_index)++; + + /* Release the sample data, once you're done with it*/ + gf_isom_sample_del(&iso_sample); + } else { + e = gf_isom_last_error(movie); + if (e == GF_ISOM_INCOMPLETE_FILE) { + missing_bytes = gf_isom_get_missing_bytes(movie, track_number); + fprintf(stdout, "Missing "LLU" bytes on input file\n", missing_bytes); + gf_sleep(1000); + } + } + } +} + +int main(int argc, char **argv) +{ + /* The ISO progressive reader */ + GF_ISOFile *movie; + /* Error indicator */ + GF_Err e; + /* Number of bytes required to finish the current ISO Box reading */ + u64 missing_bytes; + /* Return value for the program */ + int ret = 0; + /* Maximum index of the segments*/ + u32 seg_max = argc-2; + /* Number of the segment being processed*/ + u32 seg_curr = 0; + u32 track_id = 1; + u32 sample_index = 1; + + /* Usage */ + if (argc < 2) { + fprintf(stdout, "Usage: %s filename0 [filename1 filename2 ...]\n", argv[0]); + return 1; + } + +#if defined(DEBUG) || defined(_DEBUG) + /* Enables GPAC memory tracking in debug mode only */ + gf_sys_init(GF_TRUE); + gf_log_set_tool_level(GF_LOG_CONTAINER, GF_LOG_INFO); + gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); +#endif + + /* First or init segment */ + fprintf(stdout, "Process segment %5d/%5d: %s\n", seg_curr, seg_max, argv[seg_curr+1]); + e = gf_isom_open_progressive(argv[seg_curr+1], 0, 0, &movie, &missing_bytes); + if ((e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) || movie == NULL) { + fprintf(stdout, "Could not open file %s for reading (%s).\n", argv[seg_curr+1], gf_error_to_string(e)); + return 1; + } + process_samples_from_track(movie, track_id, &sample_index); + seg_curr++; + + /* Process segments */ + while (seg_curr <= seg_max) { + fprintf(stdout, "Process segment %5d/%5d: %s\n", seg_curr, seg_max, argv[seg_curr+1]); + + /* Open the segment */ + e = gf_isom_open_segment(movie, argv[seg_curr+1], 0, 0, GF_FALSE); + if (e != GF_OK) { + fprintf(stdout, "Could not open segment %s for reading (%s).\n", argv[seg_curr+1], gf_error_to_string(e)); + ret = 1; + goto exit; + } + + /* Process the segment */ + process_samples_from_track(movie, track_id, &sample_index); + + /* Release the segment */ + gf_isom_release_segment(movie, 1); + + seg_curr++; + } + +exit: + fprintf(stdout, "Total nb Samples: %d\n", gf_isom_get_sample_count(movie, gf_isom_get_track_by_id(movie, track_id) ) ); + gf_isom_release_segment(movie, 1); + gf_isom_close(movie); +#if defined(DEBUG) || defined(_DEBUG) + /* Closes GPAC memory tracking in debug mode only */ + gf_sys_close(); +#endif + + return ret; +} diff --git a/applications/testapps/segmp4demux/segmp4demux.sln b/applications/testapps/segmp4demux/segmp4demux.sln new file mode 100644 index 0000000..8430f20 --- /dev/null +++ b/applications/testapps/segmp4demux/segmp4demux.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "segmp4demux", "segmp4demux.vcxproj", "{978A2D9F-E44F-4073-8032-333563BCC160}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.ActiveCfg = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.Build.0 = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.ActiveCfg = Release|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/applications/testapps/segmp4demux/segmp4demux.vcxproj b/applications/testapps/segmp4demux/segmp4demux.vcxproj new file mode 100644 index 0000000..2dd86a9 --- /dev/null +++ b/applications/testapps/segmp4demux/segmp4demux.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {365CEAE9-305B-43C9-B531-904E500F0809} + segmp4demux + + + + Application + v110 + false + MultiByte + + + Application + v100 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + AllRules.ruleset + + + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + AllRules.ruleset + + + + + + .\Debug/segmp4demux.tlb + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + true + Level3 + true + EditAndContinue + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + MachineX86 + + + true + .\Debug/segmp4demux.bsc + + + + + .\Release/segmp4demux.tlb + + + + MaxSpeed + OnlyExplicitInline + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_CORE_TOOLS;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/segmp4demux.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) + .\Release/segmp4demux.pdb + Console + MachineX86 + + + true + .\Release/segmp4demux.bsc + + + + + + \ No newline at end of file diff --git a/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters b/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters new file mode 100644 index 0000000..4a097c1 --- /dev/null +++ b/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters @@ -0,0 +1,137 @@ + + + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + + others + + + others + + + others + + + others + + + others + + + others + + + isoff + + + others + + + + + {c9a8f639-328c-4505-be50-4859357c2c00} + + + {e5ca7285-ca00-49d8-ac81-dff3d494be9a} + + + \ No newline at end of file diff --git a/applications/testapps/svg2bifs/main.c b/applications/testapps/svg2bifs/main.c new file mode 100644 index 0000000..d13ed2f --- /dev/null +++ b/applications/testapps/svg2bifs/main.c @@ -0,0 +1,1047 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Cyril COncolato + * Copyright (c) Telecom ParisTech 2006-2012 + * All rights reserved + * + * This file is part of GPAC / svg2bifs application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +typedef struct { + GF_SAXParser *sax_parser; + + GF_SceneGraph *svg_sg; + GF_Node *svg_parent; + SVGAllAttributes all_atts; + SVGPropertiesPointers svg_props; + + GF_SceneGraph *bifs_sg; + GF_Node *bifs_parent; + GF_Node *bifs_text_node; + + Bool force_transform; + +} SVG2BIFS_Converter; + + +typedef struct { + /* Stage of the resolving: + 0: resolving attributes which depends on the target: from, to, by, values, type + 1: resolving begin times + 2: resolving end times */ + u32 resolve_stage; + /* Animation element being defered */ + SVG_Element *animation_elt; + /* anim parent*/ + SVG_Element *anim_parent; + /* target animated element*/ + SVG_Element *target; + /* id of the target element when unresolved*/ + char *target_id; + + /* attributes which cannot be parsed until the type of the target attribute is known */ + char *type; /* only for animateTransform */ + char *to; + char *from; + char *by; + char *values; +} SVG_DeferedAnimation; + + +static GF_Node *create_appearance(SVGPropertiesPointers *svg_props, GF_SceneGraph *sg) +{ + M_Appearance *app; + M_Material2D *mat; + M_XLineProperties *xlp; + M_RadialGradient *rg; + M_LinearGradient *lg; + + app = (M_Appearance *)gf_node_new(sg, TAG_MPEG4_Appearance); + + app->material = gf_node_new(sg, TAG_MPEG4_Material2D); + mat = (M_Material2D *)app->material; + gf_node_register((GF_Node*)mat, (GF_Node*)app); + + if (svg_props->fill->type == SVG_PAINT_NONE) { + mat->filled = 0; + } else { + mat->filled = 1; + if (svg_props->fill->type == SVG_PAINT_COLOR) { + if (svg_props->fill->color.type == SVG_COLOR_RGBCOLOR) { + mat->emissiveColor.red = svg_props->fill->color.red; + mat->emissiveColor.green = svg_props->fill->color.green; + mat->emissiveColor.blue = svg_props->fill->color.blue; + } else if (svg_props->fill->color.type == SVG_COLOR_CURRENTCOLOR) { + mat->emissiveColor.red = svg_props->color->color.red; + mat->emissiveColor.green = svg_props->color->color.green; + mat->emissiveColor.blue = svg_props->color->color.blue; + } else { + /* WARNING */ + mat->emissiveColor.red = 0; + mat->emissiveColor.green = 0; + mat->emissiveColor.blue = 0; + } + } else { // SVG_PAINT_URI + /* TODO: gradient or solidcolor */ + } + } + + mat->transparency = FIX_ONE - svg_props->fill_opacity->value; + + if (svg_props->stroke->type != SVG_PAINT_NONE && + svg_props->stroke_width->value != 0) { + mat->lineProps = gf_node_new(sg, TAG_MPEG4_XLineProperties); + xlp = (M_XLineProperties *)mat->lineProps; + gf_node_register((GF_Node*)xlp, (GF_Node*)mat); + + xlp->width = svg_props->stroke_width->value; + + if (svg_props->stroke->type == SVG_PAINT_COLOR) { + if (svg_props->stroke->color.type == SVG_COLOR_RGBCOLOR) { + xlp->lineColor.red = svg_props->stroke->color.red; + xlp->lineColor.green = svg_props->stroke->color.green; + xlp->lineColor.blue = svg_props->stroke->color.blue; + } else if (svg_props->stroke->color.type == SVG_COLOR_CURRENTCOLOR) { + xlp->lineColor.red = svg_props->color->color.red; + xlp->lineColor.green = svg_props->color->color.green; + xlp->lineColor.blue = svg_props->color->color.blue; + } else { + /* WARNING */ + xlp->lineColor.red = 0; + xlp->lineColor.green = 0; + xlp->lineColor.blue = 0; + } + } else { // SVG_PAINT_URI + /* TODO: xlp->texture = ... */ + } + xlp->transparency = FIX_ONE - svg_props->stroke_opacity->value; + xlp->lineCap = *svg_props->stroke_linecap; + xlp->lineJoin = *svg_props->stroke_linejoin; + if (svg_props->stroke_dasharray->type == SVG_STROKEDASHARRAY_ARRAY) { + u32 i; + xlp->lineStyle = 6; + gf_sg_vrml_mf_alloc(&xlp->dashes, GF_SG_VRML_MFFLOAT, svg_props->stroke_dasharray->array.count); + for (i = 0; i < svg_props->stroke_dasharray->array.count; i++) { + xlp->dashes.vals[i] = svg_props->stroke_dasharray->array.vals[i] / svg_props->stroke_width->value; + } + } + xlp->miterLimit = svg_props->stroke_miterlimit->value; + } + + return (GF_Node*)app; +} + + + +static GF_Node *add_transform_matrix(SVG2BIFS_Converter *converter, GF_Node *node) +{ + M_TransformMatrix2D *tr = (M_TransformMatrix2D*)gf_node_new(converter->bifs_sg, TAG_MPEG4_TransformMatrix2D); + gf_node_register((GF_Node *)tr, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, (GF_Node *)tr); + if (converter->all_atts.transform) { + SVG_Transform *svg_tr = converter->all_atts.transform; + tr->mxx = svg_tr->mat.m[0]; + tr->mxy = svg_tr->mat.m[1]; + tr->tx = svg_tr->mat.m[2]; + tr->myx = svg_tr->mat.m[3]; + tr->myy = svg_tr->mat.m[4]; + tr->ty = svg_tr->mat.m[5]; + } + return (GF_Node *)tr; + +} + +static GF_Node *add_transform2d(SVG2BIFS_Converter *converter, GF_Node *node) +{ + M_Transform2D *tr = (M_Transform2D*)gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D); + gf_node_register((GF_Node *)tr, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, (GF_Node *)tr); + return (GF_Node *)tr; +} + +static void svg_parse_animation(GF_SceneGraph *sg, SVG_DeferedAnimation *anim) +{ + GF_FieldInfo info; + u32 tag; + u8 anim_value_type = 0; + + if (anim->resolve_stage==0) { + /* Stage 0: parsing the animation attribute values + for that we need to resolve the target first */ + if (!anim->target) + anim->target = (SVG_Element *) gf_sg_find_node_by_name(sg, anim->target_id + 1); + + if (!anim->target) { + /* the target is still not known stay in stage 0 */ + return; + } else { + XMLRI *iri; + gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_XLINK_ATT_href, 1, 0, &info); + iri = (XMLRI *)info.far_ptr; + iri->type = XMLRI_ELEMENTID; + iri->target = anim->target; + gf_node_register_iri(sg, iri); + } + + tag = gf_node_get_tag((GF_Node *)anim->animation_elt); + /* get the attribute name attribute if specified */ + if (anim->type && (tag== TAG_SVG_animateTransform) ) { + gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_transform_type, 1, 0, &info); + gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->type, 0); + switch(*(SVG_TransformType *) info.far_ptr) { + case SVG_TRANSFORM_TRANSLATE: + anim_value_type = SVG_Transform_Translate_datatype; + break; + case SVG_TRANSFORM_SCALE: + anim_value_type = SVG_Transform_Scale_datatype; + break; + case SVG_TRANSFORM_ROTATE: + anim_value_type = SVG_Transform_Rotate_datatype; + break; + case SVG_TRANSFORM_SKEWX: + anim_value_type = SVG_Transform_SkewX_datatype; + break; + case SVG_TRANSFORM_SKEWY: + anim_value_type = SVG_Transform_SkewY_datatype; + break; + case SVG_TRANSFORM_MATRIX: + anim_value_type = SVG_Transform_datatype; + break; + default: + fprintf(stdout, "unknown datatype for animate transform"); + return; + } + } + else if (gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_attributeName, 0, 0, &info) == GF_OK) { + gf_node_get_attribute_by_name((GF_Node *)anim->target, ((SMIL_AttributeName *)info.far_ptr)->name, 0, 1, 1, &info); + anim_value_type = info.fieldType; + } else { + if (tag == TAG_SVG_animateMotion) { + anim_value_type = SVG_Motion_datatype; + } else if (tag == TAG_SVG_discard) { + /* there is no value to parse in discard, we can jump to the next stage */ + anim->resolve_stage = 1; + svg_parse_animation(sg, anim); + return; + } else { + fprintf(stdout, "Missing attributeName attribute on %s", gf_node_get_name((GF_Node *)anim->animation_elt)); + return; + } + } + + if (anim->to) { + gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_to, 1, 0, &info); + gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->to, anim_value_type); + } + if (anim->from) { + gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_from, 1, 0, &info); + gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->from, anim_value_type); + } + if (anim->by) { + gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_by, 1, 0, &info); + gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->by, anim_value_type); + } + if (anim->values) { + gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_values, 1, 0, &info); + gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->values, anim_value_type); + } + anim->resolve_stage = 1; + } +} + + +static void svg2bifs_node_start(void *sax_cbck, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes) +{ + u32 i; + SVG2BIFS_Converter *converter = (SVG2BIFS_Converter *)sax_cbck; + SVGPropertiesPointers *backup_props; + char *id_string = NULL; + u32 tag; + SVG_Element *elt; + SVG_DeferedAnimation *anim = NULL; + + tag = gf_xml_get_element_tag(name, 0); + elt = (SVG_Element*)gf_node_new(converter->svg_sg, tag); + if (!gf_sg_get_root_node(converter->svg_sg)) { + gf_node_register((GF_Node *)elt, NULL); + gf_sg_set_root_node(converter->svg_sg, (GF_Node *)elt); + } else { + gf_node_register((GF_Node *)elt, converter->svg_parent); + //gf_node_list_add_child(&((GF_ParentNode*)converter->svg_parent)->children, (GF_Node *)elt); + } + +// fprintf(stdout, "Converting %s\n", gf_node_get_class_name((GF_Node *)elt)); +// if (converter->bifs_parent) fprintf(stdout, "%s\n", gf_node_get_class_name(converter->bifs_parent)); + + if (gf_svg_is_animation_tag(tag)) { + GF_SAFEALLOC(anim, SVG_DeferedAnimation); + /*default anim target is parent node*/ + anim->animation_elt = elt; + if (converter->svg_parent) { + anim->target = anim->anim_parent = (SVG_Element*) converter->svg_parent; + } + } + + for (i=0; ivalue || !strlen(att->value)) continue; + + if (!stricmp(att->name, "style")) { + gf_svg_parse_style((GF_Node *)elt, att->value); + } else if (!stricmp(att->name, "id") || !stricmp(att->name, "xml:id")) { + gf_svg_parse_element_id((GF_Node *)elt, att->value, 0); + id_string = att->value; + } else if (anim && !stricmp(att->name, "to")) { + anim->to = gf_strdup(att->value); + } else if (anim && !stricmp(att->name, "from")) { + anim->from = gf_strdup(att->value); + } else if (anim && !stricmp(att->name, "by")) { + anim->by = gf_strdup(att->value); + } else if (anim && !stricmp(att->name, "values")) { + anim->values = gf_strdup(att->value); + } else if (anim && (tag == TAG_SVG_animateTransform) && !stricmp(att->name, "type")) { + anim->type = gf_strdup(att->value); + } else { + GF_FieldInfo info; + if (gf_node_get_field_by_name((GF_Node *)elt, att->name, &info)==GF_OK) { + gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0); + } else { + fprintf(stdout, "Skipping attribute %s\n", att->name); + } + } + } + + if (anim) { + svg_parse_animation(converter->svg_sg, anim); + } + + memset(&converter->all_atts, 0, sizeof(SVGAllAttributes)); + gf_svg_flatten_attributes(elt, &converter->all_atts); + + backup_props = gf_malloc(sizeof(SVGPropertiesPointers)); + memcpy(backup_props, &converter->svg_props, sizeof(SVGPropertiesPointers)); + gf_node_set_private((GF_Node *)elt, backup_props); + + gf_svg_apply_inheritance(&converter->all_atts, &converter->svg_props); + + fprintf(stdout, "START\t%s\t%s\t%s", converter->svg_parent ? gf_node_get_class_name(converter->svg_parent) : "none", converter->bifs_parent ? gf_node_get_class_name(converter->bifs_parent) : "none", name); + converter->svg_parent = (GF_Node *)elt; + if (!gf_sg_get_root_node(converter->bifs_sg)) { + if (tag == TAG_SVG_svg) { + GF_Node *node, *child; + + converter->bifs_sg->usePixelMetrics = 1; + if (converter->all_atts.width && converter->all_atts.width->type == SVG_NUMBER_VALUE) { + converter->bifs_sg->width = FIX2INT(converter->all_atts.width->value); + } else { + converter->bifs_sg->width = 320; + } + if (converter->all_atts.height && converter->all_atts.height->type == SVG_NUMBER_VALUE) { + converter->bifs_sg->height = FIX2INT(converter->all_atts.height->value); + } else { + converter->bifs_sg->height = 200; + } + + node = gf_node_new(converter->bifs_sg, TAG_MPEG4_OrderedGroup); + gf_node_register(node, NULL); + gf_sg_set_root_node(converter->bifs_sg, node); + + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_QuantizationParameter); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + { + M_QuantizationParameter *qp = (M_QuantizationParameter *)child; + qp->useEfficientCoding = 1; + } + + /* SVG to BIFS coordinate transformation */ + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Viewport); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + { + M_Viewport *vp = (M_Viewport*)child; + if (converter->all_atts.viewBox) { + vp->size.x = converter->all_atts.viewBox->width; + vp->size.y = converter->all_atts.viewBox->height; + vp->position.x = converter->all_atts.viewBox->x+converter->all_atts.viewBox->width/2; + vp->position.y = -(converter->all_atts.viewBox->y+converter->all_atts.viewBox->height/2); + } else { + vp->size.x = INT2FIX(converter->bifs_sg->width); + vp->size.y = INT2FIX(converter->bifs_sg->height); + vp->position.x = INT2FIX(converter->bifs_sg->width)/2; + vp->position.y = -INT2FIX(converter->bifs_sg->height)/2; + } + } + + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Background2D); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + { + M_Background2D *b = (M_Background2D *)child; + b->backColor.red = FIX_ONE; + b->backColor.green = FIX_ONE; + b->backColor.blue = FIX_ONE; + } + + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + { + M_Transform2D *tr = (M_Transform2D *)node; + tr->scale.y = -FIX_ONE; + } + converter->bifs_parent = node; + } + } else { + GF_Node *node, *child; + + node = converter->bifs_parent; + + switch(tag) { + case TAG_SVG_g: + { + if (converter->all_atts.transform) { + node = add_transform_matrix(converter, node); + converter->bifs_parent = node; + } else { + M_Group *g = (M_Group*)gf_node_new(converter->bifs_sg, TAG_MPEG4_Group); + gf_node_register((GF_Node *)g, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, (GF_Node *)g); + node = (GF_Node *)g; + converter->bifs_parent = node; + } + } + break; + case TAG_SVG_rect: + { + Bool is_parent_set = 0; + if (converter->all_atts.transform) { + node = add_transform_matrix(converter, node); + converter->bifs_parent = node; + is_parent_set = 1; + } + if (converter->force_transform) { + node = add_transform2d(converter, node); + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + } + if (converter->all_atts.x || converter->all_atts.y) { + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + { + M_Transform2D *tr = (M_Transform2D *)node; + if (converter->all_atts.x) tr->translation.x = converter->all_atts.x->value + (converter->all_atts.width?converter->all_atts.width->value/2:0); + if (converter->all_atts.y) tr->translation.y = converter->all_atts.y->value + (converter->all_atts.height?converter->all_atts.height->value/2:0); + } + } + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + if (!is_parent_set) converter->bifs_parent = node; + { + M_Shape *shape = (M_Shape *)node; + shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_Rectangle); + gf_node_register(shape->geometry, (GF_Node *)shape); + { + M_Rectangle *rect = (M_Rectangle *)shape->geometry; + if (converter->all_atts.width) rect->size.x = converter->all_atts.width->value; + if (converter->all_atts.height) rect->size.y = converter->all_atts.height->value; + } + + shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg); + gf_node_register(shape->appearance, (GF_Node *)shape); + } + } + break; + case TAG_SVG_path: + { + Bool is_parent_set = 0; + if (converter->all_atts.transform) { + node = add_transform_matrix(converter, node); + converter->bifs_parent = node; + is_parent_set = 1; + } + if (converter->force_transform) { + node = add_transform2d(converter, node); + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + } + if (converter->all_atts.x || converter->all_atts.y) { + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + { + M_Transform2D *tr = (M_Transform2D *)node; + if (converter->all_atts.x) tr->translation.x = converter->all_atts.x->value; + if (converter->all_atts.y) tr->translation.y = converter->all_atts.y->value; + } + } + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + if (!is_parent_set) converter->bifs_parent = node; + { + M_Shape *shape = (M_Shape *)node; + shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_XCurve2D); + gf_node_register(shape->geometry, (GF_Node *)shape); + if (converter->all_atts.d) { + M_Coordinate2D *c2d; + M_XCurve2D *xc = (M_XCurve2D *)shape->geometry; + u32 i, j, c, k; + + xc->point = gf_node_new(converter->bifs_sg, TAG_MPEG4_Coordinate2D); + c2d = (M_Coordinate2D *)xc->point; + gf_node_register(xc->point, (GF_Node *)xc); + + gf_sg_vrml_mf_alloc(&c2d->point, GF_SG_VRML_MFVEC2F, converter->all_atts.d->n_points); + gf_sg_vrml_mf_alloc(&xc->type, GF_SG_VRML_MFINT32, converter->all_atts.d->n_points); + + c = 0; + k = 0; + j = 0; + c2d->point.vals[k] = converter->all_atts.d->points[0]; + k++; + xc->type.vals[0] = 0; + for (i = 1; i < converter->all_atts.d->n_points; ) { + switch(converter->all_atts.d->tags[i]) { + case GF_PATH_CURVE_ON: + c2d->point.vals[k] = converter->all_atts.d->points[i]; + k++; + + if (i-1 == converter->all_atts.d->contours[c]) { + xc->type.vals[j] = 0; + c++; + } else { + xc->type.vals[j] = 1; + } + i++; + break; + case GF_PATH_CURVE_CUBIC: + c2d->point.vals[k] = converter->all_atts.d->points[i]; + c2d->point.vals[k+1] = converter->all_atts.d->points[i+1]; + c2d->point.vals[k+2] = converter->all_atts.d->points[i+2]; + k+=3; + + xc->type.vals[j] = 2; + if (converter->all_atts.d->tags[i+2]==GF_PATH_CLOSE) { + j++; + xc->type.vals[j] = 6; + } + i+=3; + break; + case GF_PATH_CLOSE: + xc->type.vals[j] = 6; + i++; + break; + case GF_PATH_CURVE_CONIC: + c2d->point.vals[k] = converter->all_atts.d->points[i]; + c2d->point.vals[k+1] = converter->all_atts.d->points[i+1]; + k+=2; + + xc->type.vals[j] = 7; + if (converter->all_atts.d->tags[i+1]==GF_PATH_CLOSE) { + j++; + xc->type.vals[j] = 6; + } + i+=2; + break; + } + j++; + } + xc->type.count = j; + c2d->point.count = k; + } + + shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg); + gf_node_register(shape->appearance, (GF_Node *)shape); + } + } + break; + case TAG_SVG_polyline: + { + Bool is_parent_set = 0; + if (converter->all_atts.transform) { + node = add_transform_matrix(converter, node); + converter->bifs_parent = node; + is_parent_set = 1; + } + if (converter->force_transform) { + node = add_transform2d(converter, node); + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + } + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + if (!is_parent_set) converter->bifs_parent = node; + { + M_Shape *shape = (M_Shape *)node; + shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_IndexedFaceSet2D); + gf_node_register(shape->geometry, (GF_Node *)shape); + if (converter->all_atts.points) { + M_Coordinate2D *c2d; + M_IndexedFaceSet2D *ifs = (M_IndexedFaceSet2D *)shape->geometry; + u32 i; + + ifs->coord = gf_node_new(converter->bifs_sg, TAG_MPEG4_Coordinate2D); + c2d = (M_Coordinate2D *)ifs->coord; + gf_node_register(ifs->coord, (GF_Node *)ifs); + + gf_sg_vrml_mf_alloc(&c2d->point, GF_SG_VRML_MFVEC2F, gf_list_count(*converter->all_atts.points)); + for (i = 0; i < gf_list_count(*converter->all_atts.points); i++) { + SVG_Point *p = (SVG_Point *)gf_list_get(*converter->all_atts.points, i); + c2d->point.vals[i].x = p->x; + c2d->point.vals[i].y = p->y; + } + } + + shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg); + gf_node_register(shape->appearance, (GF_Node *)shape); + } + } + break; + case TAG_SVG_text: + { + Bool is_parent_set = 0; + if (converter->all_atts.transform) { + node = add_transform_matrix(converter, node); + converter->bifs_parent = node; + is_parent_set = 1; + } + if (converter->force_transform) { + node = add_transform2d(converter, node); + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + } + + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + { + M_Transform2D *tr = (M_Transform2D *)child; + if (converter->all_atts.text_x) tr->translation.x = ((SVG_Coordinate *)gf_list_get(*converter->all_atts.text_x, 0))->value; + if (converter->all_atts.text_y) tr->translation.y = ((SVG_Coordinate *)gf_list_get(*converter->all_atts.text_y, 0))->value; + tr->scale.y = -FIX_ONE; + } + node = child; + child = NULL; + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + if (!is_parent_set) converter->bifs_parent = node; + { + M_FontStyle *fs; + M_Text *text; + M_Shape *shape = (M_Shape *)node; + text = (M_Text *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Text); + shape->geometry = (GF_Node *)text; + converter->bifs_text_node = shape->geometry; + gf_node_register(shape->geometry, (GF_Node *)shape); + + fs = (M_FontStyle *)gf_node_new(converter->bifs_sg, TAG_MPEG4_XFontStyle); + gf_node_register((GF_Node *)fs, (GF_Node*)text); + text->fontStyle = (GF_Node *)fs; + + gf_sg_vrml_mf_alloc(&fs->family, GF_SG_VRML_MFSTRING, 1); + fs->family.vals[0] = gf_strdup(converter->svg_props.font_family->value); + fs->size = converter->svg_props.font_size->value; + + shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg); + gf_node_register(shape->appearance, (GF_Node *)shape); + } + } + break; + case TAG_SVG_ellipse: + case TAG_SVG_circle: + { + Bool is_parent_set = 0; + if (converter->all_atts.transform) { + node = add_transform_matrix(converter, node); + converter->bifs_parent = node; + is_parent_set = 1; + } + if (converter->force_transform) { + node = add_transform2d(converter, node); + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + } + if (converter->all_atts.cx || converter->all_atts.cy) { + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + { + M_Transform2D *tr = (M_Transform2D *)child; + if (converter->all_atts.cx) tr->translation.x = converter->all_atts.cx->value; + if (converter->all_atts.cy) tr->translation.y = converter->all_atts.cy->value; + } + node = child; + child = NULL; + if (!is_parent_set) { + converter->bifs_parent = node; + is_parent_set = 1; + } + } + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + if (!is_parent_set) converter->bifs_parent = node; + { + M_Shape *shape = (M_Shape *)node; + if (tag == TAG_SVG_ellipse) { + M_Ellipse *e = (M_Ellipse *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Ellipse); + shape->geometry = (GF_Node *)e; + e->radius.x = converter->all_atts.rx->value; + e->radius.y = converter->all_atts.ry->value; + } else { + M_Circle *c = (M_Circle *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Circle); + shape->geometry = (GF_Node *)c; + c->radius = converter->all_atts.r->value; + } + gf_node_register(shape->geometry, (GF_Node *)shape); + + shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg); + gf_node_register(shape->appearance, (GF_Node *)shape); + } + } + break; + + case TAG_SVG_defs: + { + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Switch); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + { + M_Switch *sw = (M_Switch *)node; + sw->whichChoice = -1; + } + converter->bifs_parent = node; + } + break; + case TAG_SVG_solidColor: + { + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape); + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + converter->bifs_parent = node; + } + break; + case TAG_SVG_animateTransform: + { + GF_Node *child_ts; + if (!gf_node_get_id(node)) { + gf_node_set_id(node, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL); + } + + child_ts = gf_node_new(converter->bifs_sg, TAG_MPEG4_TimeSensor); + if (!gf_node_get_id(child_ts)) { + gf_node_set_id(child_ts, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL); + } + gf_node_register(child_ts, node); + gf_node_list_add_child(&((GF_ParentNode *)node)->children, child_ts); + { + M_TimeSensor *ts = (M_TimeSensor *)child_ts; + if (converter->all_atts.dur) { + ts->cycleInterval = converter->all_atts.dur->clock_value; + } + if (converter->all_atts.repeatCount && converter->all_atts.repeatCount->type == SMIL_REPEATCOUNT_INDEFINITE) { + ts->loop = 1; + } + } + + if (converter->all_atts.transform_type) { + GF_FieldInfo fromField, toField; + + switch (*converter->all_atts.transform_type) { + case SVG_TRANSFORM_ROTATE: + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_PositionInterpolator2D); + if (!gf_node_get_id(child)) { + gf_node_set_id(child, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL); + } + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode *)node)->children, child); + + gf_node_get_field_by_name(child_ts, "fraction_changed", &fromField); + gf_node_get_field_by_name(child, "set_fraction", &toField); + gf_sg_route_new(converter->bifs_sg, child_ts, fromField.fieldIndex, child, toField.fieldIndex); + + gf_node_get_field_by_name(child, "value_changed", &fromField); + gf_node_get_field_by_name(node, "rotationAngle", &toField); + gf_sg_route_new(converter->bifs_sg, child, fromField.fieldIndex, node, toField.fieldIndex); + { + M_PositionInterpolator2D *pi2d = (M_PositionInterpolator2D *)child; + if (converter->all_atts.keyTimes) { + SFFloat *g; + u32 count, i; + count = gf_list_count(*converter->all_atts.keyTimes); + for (i = 0; i < count; i++) { + Fixed *f = gf_list_get(*converter->all_atts.keyTimes, i); + gf_sg_vrml_mf_append(&pi2d->key, GF_SG_VRML_MFFLOAT, &g); + *g = *f; + } + } + if (converter->all_atts.values) { + SFVec2f *g; + u32 count, i; + count = gf_list_count(converter->all_atts.values->values); + for (i = 0; i < count; i++) { + SVG_Point_Angle *p; + p = gf_list_get(converter->all_atts.values->values, i); + gf_sg_vrml_mf_append(&pi2d->keyValue, GF_SG_VRML_MFVEC2F, &g); + g->x = p->x; + g->y = p->y; + } + } + } + + + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_ScalarInterpolator); + if (!gf_node_get_id(child)) { + gf_node_set_id(child, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL); + } + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode *)node)->children, child); + + gf_node_get_field_by_name(child_ts, "fraction_changed", &fromField); + gf_node_get_field_by_name(child, "set_fraction", &toField); + gf_sg_route_new(converter->bifs_sg, child_ts, fromField.fieldIndex, child, toField.fieldIndex); + + gf_node_get_field_by_name(child, "value_changed", &fromField); + gf_node_get_field_by_name(node, "center", &toField); + gf_sg_route_new(converter->bifs_sg, child, fromField.fieldIndex, node, toField.fieldIndex); + + { + M_ScalarInterpolator *si = (M_ScalarInterpolator *)child; + if (converter->all_atts.keyTimes) { + SFFloat *g; + u32 count, i; + count = gf_list_count(*converter->all_atts.keyTimes); + for (i = 0; i < count; i++) { + Fixed *f = gf_list_get(*converter->all_atts.keyTimes, i); + gf_sg_vrml_mf_append(&si->key, GF_SG_VRML_MFFLOAT, &g); + *g = *f; + } + } + if (converter->all_atts.values) { + SFFloat *g; + u32 count, i; + count = gf_list_count(converter->all_atts.values->values); + for (i = 0; i < count; i++) { + SVG_Point_Angle *p; + p = gf_list_get(converter->all_atts.values->values, i); + gf_sg_vrml_mf_append(&si->keyValue, GF_SG_VRML_MFFLOAT, &g); + *g = p->angle; + } + } + } + + break; + + case SVG_TRANSFORM_SCALE: + case SVG_TRANSFORM_TRANSLATE: + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_PositionInterpolator2D); + if (!gf_node_get_id(child)) { + gf_node_set_id(child, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL); + } + gf_node_register(child, node); + gf_node_list_add_child(&((GF_ParentNode *)node)->children, child); + + gf_node_get_field_by_name(child_ts, "fraction_changed", &fromField); + gf_node_get_field_by_name(child, "set_fraction", &toField); + gf_sg_route_new(converter->bifs_sg, child_ts, fromField.fieldIndex, child, toField.fieldIndex); + + gf_node_get_field_by_name(child, "value_changed", &fromField); + if (*converter->all_atts.transform_type == SVG_TRANSFORM_SCALE) + gf_node_get_field_by_name(node, "scale", &toField); + else + gf_node_get_field_by_name(node, "translation", &toField); + + gf_sg_route_new(converter->bifs_sg, child, fromField.fieldIndex, node, toField.fieldIndex); + { + M_PositionInterpolator2D *pi2d = (M_PositionInterpolator2D *)child; + if (converter->all_atts.keyTimes) { + SFFloat *g; + u32 count, i; + count = gf_list_count(*converter->all_atts.keyTimes); + for (i = 0; i < count; i++) { + Fixed *f = gf_list_get(*converter->all_atts.keyTimes, i); + gf_sg_vrml_mf_append(&pi2d->key, GF_SG_VRML_MFFLOAT, &g); + *g = *f; + } + } + if (converter->all_atts.values) { + SFVec2f *g; + u32 count, i; + count = gf_list_count(converter->all_atts.values->values); + for (i = 0; i < count; i++) { + SVG_Point *p; + p = gf_list_get(converter->all_atts.values->values, i); + gf_sg_vrml_mf_append(&pi2d->keyValue, GF_SG_VRML_MFVEC2F, &g); + g->x = p->x; + g->y = p->y; + } + } + } + break; + default: + fprintf(stdout, "Warning: transformation type not supported \n"); + } + } + //converter->bifs_parent = node; + } + break; + default: + { + fprintf(stdout, "Warning: element %s not supported \n", gf_node_get_class_name((GF_Node *)elt)); + child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D); + gf_node_register(child, node); + //gf_node_list_add_child(&((GF_ParentNode*)node)->children, child); + node = child; + child = NULL; + converter->bifs_parent = node; + } + break; + } + + if (id_string) + gf_node_set_id(converter->bifs_parent, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL);//gf_node_get_name((GF_Node *)elt)); + + } + fprintf(stdout, "\t%s\n", converter->bifs_parent ? gf_node_get_class_name(converter->bifs_parent) : "none"); +} + +static void svg2bifs_node_end(void *sax_cbck, const char *name, const char *name_space) +{ + SVG2BIFS_Converter *converter = (SVG2BIFS_Converter *)sax_cbck; + GF_Node *parent; + + SVGPropertiesPointers *backup_props = gf_node_get_private(converter->svg_parent); + memcpy(&converter->svg_props, backup_props, sizeof(SVGPropertiesPointers)); +// gf_free(backup_props); + gf_node_set_private(converter->svg_parent, NULL); + + if (!(gf_node_get_tag(converter->svg_parent) == TAG_SVG_animateTransform)) + converter->bifs_parent = gf_node_get_parent(converter->bifs_parent, 0); + parent = gf_node_get_parent(converter->svg_parent, 0); + gf_node_unregister(converter->svg_parent, parent); + if (!parent) gf_sg_set_root_node(converter->svg_sg, NULL); + converter->svg_parent = parent; + converter->bifs_text_node = NULL; + + fprintf(stdout, "END:\t%s\t%s\n", converter->svg_parent ? gf_node_get_class_name(converter->svg_parent) : "none", converter->bifs_parent ? gf_node_get_class_name(converter->bifs_parent) : "none"); +} + +static void svg2bifs_text_content(void *sax_cbck, const char *text_content, Bool is_cdata) +{ + SVG2BIFS_Converter *converter = (SVG2BIFS_Converter *)sax_cbck; + if (converter->bifs_text_node) { + M_Text *text = (M_Text *)converter->bifs_text_node; + gf_sg_vrml_mf_alloc(&text->string, GF_SG_VRML_MFSTRING, 1); + text->string.vals[0] = gf_strdup(text_content); + } +} + +int main(int argc, char **argv) +{ + SVG2BIFS_Converter *converter; + GF_SceneDumper *dump; + char *tmp; + + gf_sys_init(0); + + GF_SAFEALLOC(converter, SVG2BIFS_Converter); + + converter->sax_parser = gf_xml_sax_new(svg2bifs_node_start, svg2bifs_node_end, svg2bifs_text_content, converter); + converter->force_transform = 1; + + converter->svg_sg = gf_sg_new(); + gf_svg_properties_init_pointers(&converter->svg_props); + + converter->bifs_sg = gf_sg_new(); + + fprintf(stdout, "Parsing SVG File\n"); + gf_xml_sax_parse_file(converter->sax_parser, argv[1], NULL); + + fprintf(stdout, "Dumping BIFS scenegraph\n"); + tmp = strchr(argv[1], '.'); + tmp[0] = 0; + dump = gf_sm_dumper_new(converter->bifs_sg, argv[1], ' ', GF_SM_DUMP_BT); + tmp[0] = '.'; + + gf_sm_dump_graph(dump, 1, 0); + gf_sm_dumper_del(dump); + + gf_svg_properties_reset_pointers(&converter->svg_props); + + gf_sg_del(converter->svg_sg); +// gf_sg_del(converter->bifs_sg); + + gf_xml_sax_del(converter->sax_parser); + + gf_free(converter); +} diff --git a/applications/testapps/svg2bifs/svg2bifs.dsp b/applications/testapps/svg2bifs/svg2bifs.dsp new file mode 100644 index 0000000..335a2ce --- /dev/null +++ b/applications/testapps/svg2bifs/svg2bifs.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="svg2bifs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=svg2bifs - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "svg2bifs.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "svg2bifs.mak" CFG="svg2bifs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "svg2bifs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "svg2bifs - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "svg2bifs - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/svg2bifs.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "svg2bifs - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/svg2bifs.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "svg2bifs - Win32 Release" +# Name "svg2bifs - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Target +# End Project diff --git a/applications/ts2hds/Makefile b/applications/ts2hds/Makefile new file mode 100644 index 0000000..b0695e3 --- /dev/null +++ b/applications/ts2hds/Makefile @@ -0,0 +1,50 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/applications/ts2hds + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o f4v.o f4m.o + +LINKFLAGS=-L../../bin/gcc +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=ts2hds$(EXE) +else +EXT= +PROG=ts2hds +endif +LINKFLAGS+=-lgpac + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/ts2hds/f4m.c b/applications/ts2hds/f4m.c new file mode 100644 index 0000000..0a51ba1 --- /dev/null +++ b/applications/ts2hds/f4m.c @@ -0,0 +1,173 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Author: Romain Bouqueau + * Copyright (c) Romain Bouqueau 2012- + * All rights reserved + * + * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com) + * + * This file is part of GPAC / TS to HDS (ts2hds) application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ts2hds.h" + +#include + +//#define ADOBE_INLINED_BOOTSTRAP + +struct __tag_adobe_stream +{ + FILE *f; + const char *id; + const char *base_url; + u32 bitrate; +}; + +struct __tag_adobe_multirate +{ + FILE *f; + const char *id; + const char *base_url; + GF_List *streams; +}; + +static GF_Err adobe_gen_stream_manifest(AdobeStream *as) +{ + fprintf(as->f, "\n"); + fprintf(as->f, "\n"); + fprintf(as->f, "%s\n", as->id); + if (as->base_url) + fprintf(as->f, "%s\n", as->base_url); + fprintf(as->f, "\n", as->id, as->bitrate, as->id, as->bitrate); + fprintf(as->f, "\n", as->id, as->bitrate, as->bitrate, as->id, as->bitrate); + fprintf(as->f, "\n"); + + return GF_OK; +} + +AdobeMultirate *adobe_alloc_multirate_manifest(char *id) +{ + AdobeMultirate *am = gf_calloc(1, sizeof(AdobeMultirate)); + char filename[GF_MAX_PATH]; + + //default init + am->base_url = "http://localhost/hds/tmp"; + am->id = id; + sprintf(filename, "%s.f4m", am->id); + am->f = gf_fopen(filename, "wt"); + if (!am->f) { + fprintf(stderr, "Couldn't create Adobe multirate manifest file: %s\n", filename); + assert(0); + gf_free(am); + return NULL; + } + am->streams = gf_list_new(); + + //create a fake stream + { + AdobeStream *as = gf_calloc(1, sizeof(AdobeStream)); + as->id = "HD"; + as->bitrate = 100; + sprintf(filename, "%s_%s_%d.f4m", am->id, as->id, as->bitrate); + as->f = gf_fopen(filename, "wt"); + if (!as->f) { + fprintf(stderr, "Couldn't create Adobe stream manifest file: %s\n", filename); + assert(0); + gf_list_del(am->streams); + gf_free(as); + gf_free(am); + return NULL; + } + gf_list_add(am->streams, as); + } + + return am; +} + +void adobe_free_multirate_manifest(AdobeMultirate *am) +{ + u32 i; + + if (am->f) + gf_fclose(am->f); + + for (i=0; istreams); i++) { + AdobeStream *as = gf_list_get(am->streams, i); + assert(as); + if (as->f) + gf_fclose(as->f); + //TODO: base_url and id may be stored as gf_strdup in the future + gf_list_rem(am->streams, i); + gf_free(as); + } + gf_list_del(am->streams); + + gf_free(am); +} + +GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size) +{ + GF_Err e; + u32 i; +#ifdef ADOBE_INLINED_BOOTSTRAP + char bootstrap64[GF_MAX_PATH]; + u32 bootstrap64_len; +#endif + + fprintf(am->f, "\n"); + fprintf(am->f, "\n"); + fprintf(am->f, "%s\n", am->id); + fprintf(am->f, "%s\n", am->base_url); + fprintf(am->f, "live\n"); + + assert(am->streams); + for (i=0; istreams); i++) { + AdobeStream *as = gf_list_get(am->streams, i); + assert(as); +#ifdef ADOBE_INLINED_BOOTSTRAP + fprintf(am->f, "\n", as->id, as->bitrate); + bootstrap64_len = gf_base64_encode(bootstrap, bootstrap_size, bootstrap64, GF_MAX_PATH); + fwrite(bootstrap64, bootstrap64_len, 1, am->f); + if (bootstrap64_len >= GF_MAX_PATH) { + fprintf(stderr, "Bootstrap may have been truncated for stream %s_%d.\n", as->id, as->bitrate); + assert(0); + } + fprintf(am->f, "\n\n"); +#else + { + char filename[GF_MAX_PATH]; + FILE *bstfile; + sprintf(filename, "%s_%d.bootstrap", as->id, as->bitrate); + bstfile = gf_fopen(filename, "wb"); + gf_fwrite(bootstrap, bootstrap_size, 1, bstfile); + gf_fclose(bstfile); + } +#endif + e = adobe_gen_stream_manifest(as); + if (!e) { + if (!am->base_url && !as->base_url) + fprintf(stderr, "Warning: no base_url specified\n"); + + fprintf(am->f, "\n", am->id, as->id, as->bitrate, as->bitrate); + } + } + fprintf(am->f, "\n"); + + return GF_OK; +} diff --git a/applications/ts2hds/f4v.c b/applications/ts2hds/f4v.c new file mode 100644 index 0000000..c507f48 --- /dev/null +++ b/applications/ts2hds/f4v.c @@ -0,0 +1,185 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Author: Romain Bouqueau + * Copyright (c) Romain Bouqueau 2012- + * All rights reserved + * + * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com) + * + * This file is part of GPAC / TS to HDS (ts2hds) application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ts2hds.h" + +//we need to write Adobe custom boxes +#include + +GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx) +{ + GF_Err e; + GF_BitStream *bs; + + GF_AdobeFragRandomAccessBox *afra = (GF_AdobeFragRandomAccessBox*) afra_New(); + GF_AfraEntry *ae = (GF_AfraEntry*) gf_calloc(1, sizeof(GF_AfraEntry)); + GF_AdobeBootstrapInfoBox *abst = (GF_AdobeBootstrapInfoBox*) abst_New(); + GF_AdobeSegmentRunTableBox *asrt = (GF_AdobeSegmentRunTableBox*) asrt_New(); + GF_AdobeSegmentRunEntry *asre = (GF_AdobeSegmentRunEntry*) gf_calloc(1, sizeof(GF_AdobeSegmentRunEntry)); + GF_AdobeFragmentRunTableBox *afrt = (GF_AdobeFragmentRunTableBox*) afrt_New(); + GF_AdobeFragmentRunEntry *afre = (GF_AdobeFragmentRunEntry*) gf_calloc(1, sizeof(GF_AdobeFragmentRunEntry)); + + u64 init_seg_time = ctx->curr_time; + u32 seg_duration = (u32)gf_isom_get_duration(isom_file); + + //update context + ctx->curr_time += seg_duration; + + //Adobe specific boxes + //Random Access + afra->type = GF_4CC('a', 'f', 'r', 'a'); + afra->version = 0; + afra->flags = 0; + afra->long_ids = 1; + afra->long_offsets = 1; + afra->global_entries = 0; + afra->time_scale = gf_isom_get_timescale(isom_file); + + afra->entry_count = 1; + ae->time = init_seg_time; + ae->offset = 3999; + gf_list_add(afra->local_access_entries, ae); + + afra->global_entries = 0; + afra->global_entry_count = 0; + + e = gf_list_add(isom_file->TopBoxes, afra); + if (e) { + fprintf(stderr, "Impossible to write AFRA box: %s\n", gf_error_to_string(e)); + assert(0); + return e; + } + + //Bootstrap Info + abst->type = GF_4CC('a', 'b', 's', 't'); + abst->version = 0; + abst->flags = 0; + abst->bootstrapinfo_version = 1; + abst->profile = 0; + abst->live = 1; + abst->update = 0; + abst->time_scale = gf_isom_get_timescale(isom_file); + abst->current_media_time = init_seg_time+seg_duration; + abst->smpte_time_code_offset = 0; + + abst->movie_identifier = NULL; + abst->drm_data = NULL; + abst->meta_data = NULL; + + abst->server_entry_count = 0; + abst->quality_entry_count = 0; + + abst->segment_run_table_count = 1; + { + //Segment Run + asrt->type = GF_4CC('a', 's', 'r', 't'); + asrt->version = 0; + asrt->flags = 0; + asrt->segment_run_entry_count = 1; + { + asre->first_segment = ctx->segnum; + asre->fragment_per_segment = 1; + } + e = gf_list_add(asrt->segment_run_entry_table, asre); + if (e) { + fprintf(stderr, "Impossible to write ASR Entry: %s\n", gf_error_to_string(e)); + assert(0); + return e; + } + } + e = gf_list_add(abst->segment_run_table_entries, asrt); + if (e) { + fprintf(stderr, "Impossible to write ASRT box: %s\n", gf_error_to_string(e)); + assert(0); + return e; + } + + abst->fragment_run_table_count = 1; + { + //Fragment Run + afrt->type = GF_4CC('a', 'f', 'r', 't'); + afrt->version = 0; + afrt->flags = 0; + afrt->timescale = gf_isom_get_timescale(isom_file); + afrt->fragment_run_entry_count = 1; + { + afre->first_fragment = 1; + afre->first_fragment_timestamp = 0; + afre->fragment_duration = seg_duration; + } + e = gf_list_add(afrt->fragment_run_entry_table, afre); + if (e) { + fprintf(stderr, "Impossible to write AFR Entry: %s\n", gf_error_to_string(e)); + assert(0); + return e; + } + } + e = gf_list_add(abst->fragment_run_table_entries, afrt); + if (e) { + fprintf(stderr, "Impossible to write AFRT box: %s\n", gf_error_to_string(e)); + assert(0); + return e; + } + + e = gf_list_add(isom_file->TopBoxes, abst); + if (e) { + fprintf(stderr, "Impossible to write ABST box: %s\n", gf_error_to_string(e)); + assert(0); + return e; + } + + e = abst_Size((GF_Box*)abst); + if (e) { + fprintf(stderr, "Impossible to compute ABST box size: %s\n", gf_error_to_string(e)); + assert(0); + return e; + } + ctx->bootstrap_size = (size_t)abst->size; + ctx->bootstrap = gf_malloc(ctx->bootstrap_size); + bs = gf_bs_new(ctx->bootstrap, ctx->bootstrap_size, GF_BITSTREAM_WRITE); + e = abst_Write((GF_Box*)abst, bs); + if (e) { + fprintf(stderr, "Impossible to code the ABST box: %s\n", gf_error_to_string(e)); + assert(0); + gf_bs_del(bs); + return e; + } + gf_bs_del(bs); + + //set brands as reversed engineered from f4v files + /*e = gf_isom_reset_alt_brands(isom_file); + if (e) { + fprintf(stderr, "Warning: couldn't reset ISOM brands: %s\n", gf_error_to_string(e)); + assert(0); + }*/ + gf_isom_set_brand_info(isom_file, GF_4CC('f','4','v',' '), 1); + gf_isom_modify_alternate_brand(isom_file, GF_4CC('i','s','o','m'), 1); + gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','p','4','2'), 1); + gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','4','v',' '), 1); + + return GF_OK; +} \ No newline at end of file diff --git a/applications/ts2hds/main.c b/applications/ts2hds/main.c new file mode 100644 index 0000000..6a707c8 --- /dev/null +++ b/applications/ts2hds/main.c @@ -0,0 +1,304 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Author: Romain Bouqueau + * Copyright (c) Romain Bouqueau 2012- + * All rights reserved + * + * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com) + * + * This file is part of GPAC / TS to HDS (ts2hds) application + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ts2hds.h" + +//FIXME: test only +//#include +//#include + +#ifdef WIN32 +#define strnicmp _strnicmp +#endif + +#define CHECK_NEXT_ARG if (i+1==(u32)argc) { fprintf(stderr, "Missing arg - please check usage\n"); exit(1); } + +#ifdef GPAC_DISABLE_ISOM + +#error "Cannot compile TS2HDS if GPAC is not built with ISO File Format support" + +#endif + + +static GFINLINE void usage(const char * progname) +{ + fprintf(stderr, "USAGE: %s -i input -o output\n" + "\n" +#ifdef GPAC_MEMORY_TRACKING + "\t-mem-track: enables memory tracker\n" +#endif + , progname); +} + + +/*parse TS2HDS arguments*/ +static GFINLINE GF_Err parse_args(int argc, char **argv, char **input, char **output, u64 *curr_time, u32 *segnum) +{ + Bool input_found=0, output_found=0; + char *arg = NULL, *error_msg = "no argument found"; + s32 i; + + for (i=1; isize = bootstrap[2]*256+bootstrap[3]; + assert(abst->size + +//f4m +typedef struct __tag_adobe_stream AdobeStream; +typedef struct __tag_adobe_multirate AdobeMultirate; +AdobeMultirate *adobe_alloc_multirate_manifest(char *id); +void adobe_free_multirate_manifest(AdobeMultirate *am); +GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size); + +//context +typedef struct +{ + u64 curr_time; + u32 segnum; + char *bootstrap; + size_t bootstrap_size; + AdobeMultirate *multirate_manifest; +} AdobeHDSCtx; + +//f4v +GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx); diff --git a/applications/udptsseg/Makefile b/applications/udptsseg/Makefile new file mode 100644 index 0000000..8732643 --- /dev/null +++ b/applications/udptsseg/Makefile @@ -0,0 +1,70 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/applications/udptsseg + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS= main.o + +LINKFLAGS=-L../../bin/gcc -L../../extra_lib/lib/gcc + +ifeq ($(CONFIG_WIN32),yes) +EXE=.exe +PROG=udptsseg$(EXE) +ifeq ($(MP4BOX_STATIC),yes) +LINKFLAGS+=-lgpac_static -lz $(EXTRALIBS) +else +LINKFLAGS+=-lgpac +endif +else +EXT= +PROG=udptsseg +ifeq ($(MP4BOX_STATIC),yes) +LINKFLAGS+=-lgpac_static -lz $(EXTRALIBS) +else +LINKFLAGS+=-lgpac +endif +endif + +#3 - spidermonkey support +ifeq ($(CONFIG_JS),no) +else +SCENEGRAPH_CFLAGS+=$(JS_FLAGS) +ifeq ($(CONFIG_JS),local) +NEED_LOCAL_LIB="yes" +endif +LINKFLAGS+=$(JS_LIBS) +endif + + +SRCS := $(OBJS:.o=.c) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + +clean: + rm -f $(OBJS) ../../bin/gcc/$(PROG) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/applications/udptsseg/main.c b/applications/udptsseg/main.c new file mode 100644 index 0000000..5f41603 --- /dev/null +++ b/applications/udptsseg/main.c @@ -0,0 +1,314 @@ +/* +* GPAC - Multimedia Framework C SDK +* + * Authors: Cyril COncolato, Romain Bouqueau + * Copyright (c) Telecom ParisTech 2008-2012 +* All rights reserved +* +* This file is part of GPAC / udp TS segmenter (udptsseg) application +* +* GPAC is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* GPAC is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*/ +#include +#include +#include +#include +#include + +#define UDP_BUFFER_SIZE 64484 + +/* adapted from http://svn.assembla.com/svn/legend/segmenter/segmenter.c */ +static GF_Err write_manifest(char *manifest, char *segment_dir, u32 segment_duration, char *segment_prefix, char *http_prefix, + u32 first_segment, u32 last_segment, Bool end) { + FILE *manifest_fp; + u32 i; + char manifest_tmp_name[GF_MAX_PATH]; + char manifest_name[GF_MAX_PATH]; + char *tmp_manifest = manifest_tmp_name; + + if (segment_dir) { + sprintf(manifest_tmp_name, "%stmp.m3u8", segment_dir); + sprintf(manifest_name, "%s%s", segment_dir, manifest); + } else { + sprintf(manifest_tmp_name, "tmp.m3u8"); + sprintf(manifest_name, "%s", manifest); + } + + manifest_fp = gf_fopen(tmp_manifest, "w"); + if (!manifest_fp) { + fprintf(stderr, "Could not create m3u8 manifest file (%s)\n", tmp_manifest); + return GF_BAD_PARAM; + } + + fprintf(manifest_fp, "#EXTM3U\n#EXT-X-TARGETDURATION:%u\n#EXT-X-MEDIA-SEQUENCE:%u\n", segment_duration, first_segment); + + for (i = first_segment; i <= last_segment; i++) { + fprintf(manifest_fp, "#EXTINF:%u,\n%s%s_%u.ts\n", segment_duration, http_prefix, segment_prefix, i); + } + + if (end) { + fprintf(manifest_fp, "#EXT-X-ENDLIST\n"); + } + gf_fclose(manifest_fp); + + if (!rename(tmp_manifest, manifest_name)) { + return GF_OK; + } else { + if (remove(manifest_name)) { + fprintf(stdout, "Error removing file %s\n", manifest_name); + return GF_IO_ERR; + } else if (rename(tmp_manifest, manifest_name)) { + fprintf(stderr, "Could not rename temporary m3u8 manifest file (%s) into %s\n", tmp_manifest, manifest_name); + return GF_IO_ERR; + } else { + return GF_OK; + } + } +} + +void usage() +{ + fprintf(stderr, "usage: udptsseg -src=UDP -dst-file=FILE -segment-duration=DUR -segment-dir=DIR -segment-manifest=M3U8 -segment-http-prefix=P -segment-number=N\n" + "-src=UDP udp://address:port providing the input transport stream\n" + "-dst-file=FILE e.g. out.ts, radical name of all segments\n" + "-segment-dir=DIR server local directory to store segments (with the trailing path separator)\n" + "-segment-duration=DUR segment duration in seconds\n" + "-segment-manifest=M3U8 m3u8 file basename\n" + "-segment-http-prefix=P client address for accessing server segments\n" + "-segment-number=N only n segments are used using a cyclic pattern\n" + "\n"); +} + +int main(int argc, char **argv) +{ + u32 i; + char *arg = NULL; + char *ts_in = NULL; + char *segment_dir = NULL; + char *segment_manifest = NULL; + char *segment_http_prefix = NULL; + u32 run_time = 0; + char *input_ip = NULL; + u32 input_port = 0; + GF_Socket *input_udp_sk = NULL; + char *input_buffer = NULL; + u32 input_buffer_size = UDP_BUFFER_SIZE; + GF_Err e = GF_OK; + FILE *ts_output_file = NULL; + char *ts_out = NULL; + char segment_prefix[GF_MAX_PATH]; + char segment_name[GF_MAX_PATH]; + u32 segment_duration = 0; + u32 segment_index = 0; + u32 segment_number = 0; + char segment_manifest_default[GF_MAX_PATH]; + u32 run = 1; + u32 last_segment_time = 0; + u32 last_segment_size = 0; + u32 read = 0; + u32 towrite = 0; + u32 leftinbuffer = 0; + + fprintf(stdout, "UDP Transport Stream Segmenter\n"); + + if (argc < 7) { + usage(); + return 0; + } + /*****************/ + /* gpac init */ + /*****************/ + gf_sys_init(0); + + /*****************/ + /* parsing of the arguments */ + /*****************/ + for (i = 1; i < (u32) argc ; i++) { + arg = argv[i]; + if (!strnicmp(arg, "-src=udp://",11)) { + char *sep; + arg+=11; + sep = strchr(arg+6, ':'); + if (sep) { + input_port = atoi(sep+1); + sep[0]=0; + input_ip = gf_strdup(arg); + sep[0]=':'; + } else { + input_ip = gf_strdup(arg); + } + + } else if (!strnicmp(arg, "-time=", 6)) { + run_time = atoi(arg+6); + } else if (!strnicmp(arg, "-dst-file=", 10)) { + ts_out = gf_strdup(arg+10); + } else if (!strnicmp(arg, "-segment-dir=", 13)) { + segment_dir = gf_strdup(arg+13); + } else if (!strnicmp(arg, "-segment-duration=", 18)) { + segment_duration = atoi(arg+18); + } else if (!strnicmp(arg, "-segment-manifest=", 18)) { + segment_manifest = gf_strdup(arg+18); + } else if (!strnicmp(arg, "-segment-http-prefix=", 21)) { + segment_http_prefix = gf_strdup(arg+21); + } else if (!strnicmp(arg, "-segment-number=", 16)) { + segment_number = atoi(arg+16); + } + } + fprintf(stdout, "Listening to TS input on %s:%d\n", input_ip, input_port); + fprintf(stdout, "Creating %d sec. segments in directory %s\n", segment_duration, segment_dir); + fprintf(stdout, "Creating %s manifest with %d segments\n", segment_manifest, segment_number); + + /*****************/ + /* creation of the input socket */ + /*****************/ + input_udp_sk = gf_sk_new(GF_SOCK_TYPE_UDP); + if (gf_sk_is_multicast_address((char *)input_ip)) { + e = gf_sk_setup_multicast(input_udp_sk, (char *)input_ip, input_port, 32, 0, NULL); + } else { + e = gf_sk_bind(input_udp_sk, NULL, input_port, (char *)input_ip, input_port, GF_SOCK_REUSE_PORT); + } + if (e) { + fprintf(stdout, "Error initializing UDP socket for %s:%d : %s\n", input_ip, input_port, gf_error_to_string(e)); + goto exit; + } + gf_sk_set_buffer_size(input_udp_sk, 0, UDP_BUFFER_SIZE); + gf_sk_set_block_mode(input_udp_sk, 1); + + /*****************/ + /* Initialisation of the TS and Manifest files */ + /*****************/ + + if (segment_duration) { + char *dot; + strcpy(segment_prefix, ts_out); + dot = strrchr(segment_prefix, '.'); + dot[0] = 0; + if (segment_dir) { + if (strchr("\\/", segment_name[strlen(segment_name)-1])) { + sprintf(segment_name, "%s%s_%d.ts", segment_dir, segment_prefix, segment_index); + } else { + sprintf(segment_name, "%s%c%s_%d.ts", segment_dir, GF_PATH_SEPARATOR, segment_prefix, segment_index); + } + } else { + sprintf(segment_name, "%s_%d.ts", segment_prefix, segment_index); + } + fprintf(stderr, "Processing %s segment\r", segment_name); + ts_out = gf_strdup(segment_name); + if (!segment_manifest) { + sprintf(segment_manifest_default, "%s.m3u8", segment_prefix); + segment_manifest = segment_manifest_default; + } + //write_manifest(segment_manifest, segment_dir, segment_duration, segment_prefix, segment_http_prefix, segment_index, 0, 0); + } + ts_output_file = gf_fopen(ts_out, "wb"); + if (!ts_output_file) { + fprintf(stderr, "Error opening %s\n", ts_out); + goto exit; + } + + /*allocate data buffer*/ + input_buffer = (char*)gf_malloc(input_buffer_size); + assert(input_buffer); + + /*****************/ + /* main loop */ + /*****************/ + last_segment_time = gf_sys_clock(); + last_segment_size = 0; + while (run) { + /*check for some input from the network*/ + if (input_ip) { + gf_sk_receive(input_udp_sk, input_buffer+leftinbuffer, input_buffer_size-leftinbuffer, 0, &read); + leftinbuffer += read; + if (leftinbuffer) { + fprintf(stderr, "Processing %s segment ... received %d bytes (buffer: %d, segment: %d)\n", segment_name, read, leftinbuffer, last_segment_size); + if (input_buffer[0] != 0x47) { + u32 i = 0; + while (input_buffer[i] != 0x47 && i < leftinbuffer) i++; + fprintf(stderr, "Warning: data in buffer not starting with the MPEG-2 TS sync byte, skipping %d bytes of %d\n", i, leftinbuffer); + if (i < leftinbuffer) memmove(input_buffer, input_buffer+i, leftinbuffer-i); + leftinbuffer -=i; + } + if ((leftinbuffer % 188) != 0) { + fprintf(stderr, "Warning: data in buffer with a size (%d bytes) not multiple of 188 bytes\n", leftinbuffer); + towrite = leftinbuffer - (leftinbuffer % 188); + } else { + towrite = leftinbuffer; + } + } else { + towrite = 0; + } + /*write to current file */ + if (ts_output_file != NULL) { + u32 now = gf_sys_clock(); + if (towrite) { + gf_fwrite(input_buffer, 1, towrite, ts_output_file); + if (towrite < leftinbuffer) { + fprintf(stderr, "Warning: wrote %d bytes, keeping %d bytes\n", towrite, (leftinbuffer-towrite)); + memmove(input_buffer, input_buffer+towrite, leftinbuffer-towrite); + } + leftinbuffer -= towrite; + last_segment_size += towrite; + } + if ((now - last_segment_time) > segment_duration*1000) { + last_segment_time = now; + gf_fclose(ts_output_file); + fprintf(stderr, "Closing segment %s (%d bytes)\n", segment_name, last_segment_size); + last_segment_size = 0; + segment_index++; + if (segment_dir) { + if (strchr("\\/", segment_name[strlen(segment_name)-1])) { + sprintf(segment_name, "%s%s_%d.ts", segment_dir, segment_prefix, segment_index); + } else { + sprintf(segment_name, "%s%c%s_%d.ts", segment_dir, GF_PATH_SEPARATOR, segment_prefix, segment_index); + } + } else { + sprintf(segment_name, "%s_%d.ts", segment_prefix, segment_index); + } + ts_output_file = gf_fopen(segment_name, "wb"); + if (!ts_output_file) { + fprintf(stderr, "Error opening segment %s\n", segment_name); + goto exit; + } + /* delete the oldest segment */ + if (segment_number && ((s32) (segment_index - segment_number - 1) >= 0)) { + char old_segment_name[GF_MAX_PATH]; + if (segment_dir) { + if (strchr("\\/", segment_name[strlen(segment_name)-1])) { + sprintf(old_segment_name, "%s%s_%d.ts", segment_dir, segment_prefix, segment_index - segment_number - 1); + } else { + sprintf(old_segment_name, "%s/%s_%d.ts", segment_dir, segment_prefix, segment_index - segment_number - 1); + } + } else { + sprintf(old_segment_name, "%s_%d.ts", segment_prefix, segment_index - segment_number - 1); + } + gf_delete_file(old_segment_name); + fprintf(stderr, "Deleting segment %s\n", old_segment_name); + } + write_manifest(segment_manifest, segment_dir, segment_duration, segment_prefix, segment_http_prefix, + // (segment_index >= segment_number/2 ? segment_index - segment_number/2 : 0), segment_index >1 ? segment_index-1 : 0, 0); + ( (segment_index > segment_number ) ? segment_index - segment_number : 0), segment_index >1 ? segment_index-1 : 0, 0); + } + } + + //} + } + /*cpu load regulation*/ + gf_sleep(1); + } +exit: + return 0; +} diff --git a/applications/udptsseg/udptsseg.dsp b/applications/udptsseg/udptsseg.dsp new file mode 100644 index 0000000..5b39e61 --- /dev/null +++ b/applications/udptsseg/udptsseg.dsp @@ -0,0 +1,94 @@ +# Microsoft Developer Studio Project File - Name="udptsseg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=udptsseg - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "udptsseg.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "udptsseg.mak" CFG="udptsseg - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "udptsseg - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "udptsseg - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "udptsseg - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/udptsseg.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "udptsseg - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/udptsseg.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "udptsseg - Win32 Release" +# Name "udptsseg - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +# End Source File +# End Target +# End Project diff --git a/applications/udptsseg/udptsseg.vcproj b/applications/udptsseg/udptsseg.vcproj new file mode 100644 index 0000000..903fc49 --- /dev/null +++ b/applications/udptsseg/udptsseg.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/smartphone 2003 (armv4)/release/install/archive.bat b/bin/smartphone 2003 (armv4)/release/install/archive.bat new file mode 100644 index 0000000..6306933 --- /dev/null +++ b/bin/smartphone 2003 (armv4)/release/install/archive.bat @@ -0,0 +1,16 @@ +set OLDDIR=%CD% +cd /d %~dp0 + +for /f "delims=" %%a in ('git describe --tags --long') do @set VERSION=%%a +for /f "delims=" %%a in ('git describe --tags --abbrev=0') do @set TAG=%%a- +for /f "delims=" %%a in ('git rev-parse --abbrev-ref HEAD') do @set BRANCH=%%a +REM remove anotated tag from VERSION +setlocal enabledelayedexpansion +call set VERSION=%%VERSION:!TAG!=%% +setlocal disabledelayedexpansion +set revision="%VERSION%-%BRANCH%" +set gpac_version="0.5.2-DEV-r%gpac_revision%" + +zip "GPAC_%gpac_version%_WindowsMobile.zip" ../*.dll ../*.exe ../*.plg + +cd /d %OLDDIR% diff --git a/bin/smartphone 2003 (armv4)/release/install/build_installer.bat b/bin/smartphone 2003 (armv4)/release/install/build_installer.bat new file mode 100644 index 0000000..f7a53cf --- /dev/null +++ b/bin/smartphone 2003 (armv4)/release/install/build_installer.bat @@ -0,0 +1,42 @@ +set OLDDIR=%CD% +cd /d %~dp0 + +for /f "delims=" %%a in ('git describe --tags --long') do @set VERSION=%%a +for /f "delims=" %%a in ('git describe --tags --abbrev=0') do @set TAG=%%a- +for /f "delims=" %%a in ('git rev-parse --abbrev-ref HEAD') do @set BRANCH=%%a +REM remove anotated tag from VERSION +setlocal enabledelayedexpansion +call set VERSION=%%VERSION:!TAG!=%% +setlocal disabledelayedexpansion +set revision="%VERSION%-%BRANCH%" + +set gpac_version="0.5.2-DEV-r%gpac_revision%" + +ECHO [Version] > gpaccab.inf +ECHO Provider = "GPAC %gpac_version%" >> gpaccab.inf +type gpac.inf >> gpaccab.inf + +CabWiz gpaccab.inf + +ECHO off + +ECHO [CEAppManager]> gpac.ini +ECHO Version = %gpac_version%>> gpac.ini +ECHO Component = GPAC for Windows Mobile>> gpac.ini +ECHO [GPAC for Windows Mobile]>> gpac.ini +ECHO Description = GPAC MPEG-4 Player>> gpac.ini +ECHO Uninstall = GPAC Osmophone>> gpac.ini +ECHO IconFile = ..\..\..\..\doc\osmo4.ico>> gpac.ini +ECHO IconIndex = 0 >> gpac.ini +ECHO CabFiles = gpaccab.cab >> gpac.ini + +ECHO on + +ezsetup -l english -i gpac.ini -r readme.txt -e ../../../../COPYING -o gpac.exe +rename gpac.exe "GPAC_%gpac_version%_WindowsMobile.exe" +DEL gpaccab.cab +DEL gpaccab.inf +DEL gpac.ini +DEL *.tmp + +cd /d %OLDDIR% diff --git a/bin/smartphone 2003 (armv4)/release/install/gpac.inf b/bin/smartphone 2003 (armv4)/release/install/gpac.inf new file mode 100644 index 0000000..870c6ea --- /dev/null +++ b/bin/smartphone 2003 (armv4)/release/install/gpac.inf @@ -0,0 +1,148 @@ +;[Version] +Signature = "$Windows NT$" +CESignature = "$Windows CE$" + +[CEStrings] +;Osmo4 for PocketPC install, Osmophone for Smartphone install +AppName = Osmophone +InstallDir = \Program Files\GPAC + +[Strings] +;Osmo4.exe for PocketPC install, Osmophone.exe for Smartphone install +ExeName = Osmophone.exe + +[DefaultInstall] +CopyFiles = BinFiles , Exefiles +AddReg = GPACReg +CEShortcuts = Shortcut , ProgLink +CESelfRegister=GPAX.dll + + +[SourceDisksNames] + +1 =, "Common Files",, .. +2 =, "Extra Files",, . +3 =, "Doc Files",, ..\..\..\..\doc\ + +[SourceDisksFiles] +libgpac.dll = 1 +%ExeName% = 1 +;Osmo4.exe = 1 +GPAX.dll = 1 +gpac.mp4 = 3 + +msvcr80.dll = 1 + +;comment this one if not using OpenGL +libGLES_CM.dll = 1 + +;comment this one if not using SpiderMonkey +js32.dll = 1 + +;uncomment if your device doesn't have GX installed (I think most do) +;gx.dll = 2 + +;all gpac modules - comment the ones you haven't compiled +gm_aac_in.dll = 1 +gm_bifs_dec.dll = 1 +gm_ctx_load.dll = 1 +gm_dummy_in.dll = 1 +gm_ft_font.dll = 1 +gm_gapi.dll = 1 +gm_gpac_js.dll = 1 +gm_img_in.dll = 1 +gm_ismacryp.dll = 1 +gm_isom_in.dll = 1 +gm_laser_dec.dll = 1 +gm_mp3_in.dll = 1 +gm_mpegts_in.dll = 1 +gm_odf_dec.dll = 1 +gm_platinum.dll = 1 +gm_rtp_in.dll = 1 +gm_timedtext.dll = 1 +gm_soft_raster.dll = 1 +gm_svg_in.dll = 1 +gm_wav_out.dll = 1 +gm_widgetman.dll = 1 +gm_xvid_dec.dll = 1 +gm_ogg.dll = 1 +;commenting out ffmpeg since we no longer have a recent version (and no one uses smartphone 2003 anymore ...) +;gm_ffmpeg_in.dll = 1 +;avcodec-52.dll = 1 +;avformat-52.dll = 1 +;avutil-50.dll = 1 +;swscale-0.dll = 1 + +;================================================== + + + +; Ouput directories for files & shortcuts + +[DestinationDirs] +BinFiles = 0, %CE2% +Exefiles = 0, %InstallDir% +Shortcut = 0, %CE17% +ProgLink = 0, %CE11% +DefaultDestDir = 0, %InstallDir% + +[BinFiles] +;"gx.dll" +"libgpac.dll" +"GPAX.dll" +"js32.dll" +"libGLES_CM.dll" +"msvcr80.dll" + +[Exefiles] +"%ExeName%" +"gpac.mp4" +"gm_aac_in.dll" +"gm_bifs_dec.dll" +"gm_ctx_load.dll" +"gm_dummy_in.dll" +"gm_ffmpeg_in.dll" +"avcodec-52.dll" +"avformat-52.dll" +"avutil-50.dll" +"swscale-0.dll" +"gm_ft_font.dll" +"gm_gapi.dll" +"gm_gpac_js.dll" +"gm_img_in.dll" +"gm_ismacryp.dll" +"gm_isom_in.dll" +"gm_laser_dec.dll" +"gm_mp3_in.dll" +"gm_mpegts_in.dll" +"gm_odf_dec.dll" +"gm_platinum.dll" +"gm_rtp_in.dll" +"gm_timedtext.dll" +"gm_soft_raster.dll" +"gm_svg_in.dll" +"gm_wav_out.dll" +"gm_widgetman.dll" +"gm_xvid_dec.dll" +"gm_ogg.dll" + +[GPACReg] +;GPAC cfg file location +HKCR,GPAC,InstallDir,0x00000000,%InstallDir% + +;GPAC cfg file association +HKCR,.cfg,,0x00000000,txtfile + +;MP4 file association +HKCR,.mp4,,0x00000000,mp4file +HKCR,mp4file\Shell\Open\Command,,0x00000000,"""%InstallDir%\%ExeName%""" """%%L""" + +;Icon number is bin ID of ressource in app +HKCR,mp4file\DefaultIcon,,0x00000000,"%InstallDir%\%ExeName%,-128" + +[Shortcut] +"%AppName%", 0, "%ExeName%" + +[ProgLink] +"%AppName%", 0, "%ExeName%" + diff --git a/bin/smartphone 2003 (armv4)/release/install/readme.txt b/bin/smartphone 2003 (armv4)/release/install/readme.txt new file mode 100644 index 0000000..43ce565 --- /dev/null +++ b/bin/smartphone 2003 (armv4)/release/install/readme.txt @@ -0,0 +1,6 @@ +This will install GPAC for ARM PocketPC/SmartPhones 2003 Platforms + +GPAC is an open source MPEG-4 framework developped by ENST and available at: + http://gpac.sourceforge.net + +WARNING: THIS RELEASE COMES WITH NO WARRANTY, AND MAY EVEN DAMAGE YOUR HANDHELD DEVICE. PLEASE READ CAREFULLY THE LICENSE HEREJOIN diff --git a/configure b/configure new file mode 100755 index 0000000..55d7b4c --- /dev/null +++ b/configure @@ -0,0 +1,3361 @@ +#!/bin/sh +# +# GPAC configure script +# (c) 2003-2012 Telecom ParisTech +# Authors: Jean Le Feuvre, Romain Bouqueau +# +#set -v + + +#set temporary file name +if test ! -z "$TMPDIR" ; then + TMPDIR1="${TMPDIR}" +elif test ! -z "$TEMPDIR" ; then + TMPDIR1="${TEMPDIR}" +else + TMPDIR1="/tmp" +fi + + +#remember the ./configure command line +GPAC_CONFIGURATION="$@" + +TMPC="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.c" +TMPH="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.h" +TMPCXX="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.cpp" +TMPE="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}" +TMPO="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.o" +TMPS="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.S" +TMPL="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.LOG" + + +#default parameters +DESTDIR="" +prefix="/usr/local" +mandir="" +cross_prefix="" +targetos="" +dxsdk_path="" +moz_path="local" +cc_orig="gcc" +cxx_orig="g++" +ar="ar" +ranlib="ranlib" +make="make" +strip="strip" +pkg_config="pkg-config" +windres="windres" +readelf="readelf" +install="${INSTALL:=install}" +instflags="${INSTFLAGS:=-p}" +cpu=`uname -m` +debuginfo="no" +sdl_path="" +sdl_local="no" +sdl_static="no" +verbose="no" +xulsdk_path="/usr/lib/xulrunner/sdk/include" +xul_flags="" +libdir="lib" + +#GPAC module config +static_modules="no" +js_flags="XP_UNIX" +js_lib="-ljs" +lm_lib="" +has_mingw_directx="no" +has_js="no" +has_platinum="no" +has_ft="no" +has_jpeg="no" +has_png="no" +has_xvid="no" +has_mad="no" +has_faad="no" +has_ffmpeg="no" +has_amr_nb_fixed="no" +has_amr_nb="no" +has_amr_wb="no" +has_ogg="no" +has_vorbis="no" +has_theora="no" +has_a52="no" +has_pulseaudio="no" +has_oss_audio="no" +has_alsa="no" +has_jack="no" +has_directfb="no" +has_x11="no" +has_x11_shm="no" +has_x11_xv="no" +no_gcc_opt="no" +use_fixed_point="no" +use_memory_tracking="no" +has_opengl="no" +has_tinygl="no" +enable_tinygl="no" +has_ssl="no" +has_ipv6="no" +has_dvb4linux="no" +has_xmlrpc="no" +has_openjpeg="no" +gprof_build="no" +static_build="no" +want_pic="no" +want_gcov="no" +has_joystick="no" +has_xul="no" +enable_joystick="no" +static_mp4box="no" +disable_core_tools="no" +disable_3d="no" +disable_svg="no" +disable_vrml="no" +disable_x3d="no" +disable_od="no" +disable_bifs="no" +disable_bifs_enc="no" +disable_laser="no" +disable_saf="no" +disable_smgr="no" +disable_seng="no" +disable_qtvr="no" +disable_avi="no" +disable_m2ps="no" +disable_m2ts="no" +disable_m2ts_mux="no" +disable_ogg="no" +disable_parsers="no" +disable_import="no" +disable_export="no" +disable_swf="no" +disable_scene_stats="no" +disable_scene_dump="no" +disable_scene_encode="no" +disable_loader_isoff="no" +disable_loader_bt="no" +disable_loader_xmt="no" +disable_od_dump="no" +disable_od_parse="no" +disable_isom_dump="no" +disable_mcrypt="no" +disable_mpd="no" +disable_dash="no" +disable_isoff="no" +disable_isoff_write="no" +disable_isoff_frag="no" +disable_isoff_hint="no" +disable_isoff_frag="no" +disable_isoff_hds="no" +disable_streaming="no" +disable_player="no" +disable_scenegraph="no" +disable_dvbx="yes" +disable_vobsub="no" +disable_ttxt="no" +disable_ttml="no" +disable_hevc="no" +enable_depth_compositor="no" +enable_renoir="no" +has_avcap="no" +avcap_cflags="" +avcap_ldflags="-lavcap" +has_opensvc="no" +has_openhevc="no" + +win32="no" +mingw32="no" +cygwin="no" +linux="no" +freebsd="no" +darwin="no" +sunos="no" +alt_macosx_dir="" +Mac_Applications="" +extralibs="-lm" +bigendian="no" +SHFLAGS=-shared +need_inet_aton="no" +CFLAGS="" +CXXFLAGS="" +GPAC_SH_FLAGS=-lpthread +DYN_LIB_SUFFIX=".so" +X11_PATH="/usr/X11R6" +OSS_CFLAGS="" +OSS_LDFLAGS="" +INSTFLAGS="" +is_64="no" +ffmpeg_extra_ldflags="" + +logs="config.log" +echo "Logs for GPAC configure $GPAC_CONFIGURATION" > $logs + + +#configure usage +if test x"$1" = x"-h" -o x"$1" = x"--help" ; then + cat << EOF + +Usage: configure [options] +Options: [defaults in brackets after descriptions] + +GPAC configuration options: + --help print this message + --prefix=PREFIX install in PREFIX [$prefix] + --mandir=DIR man documentation in DIR [PREFIX/man] + + --verbose enable verbose building [$verbose] + --source-path=PATH path of source code [$source_path] + --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix] + --target-os=TARGETOS use TARGETOS for compile tools [$targetos] + --cc=CC use C compiler CC [$cc] + --cxx=CXX use C++ compiler CXX [$cxx] + --make=MAKE use specified make [$make] + --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS] + --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS] + --extra-libs=ELIBS add ELIBS [$ELIBS] + --cpu=CPU force cpu to CPU [$cpu] + --sdl-cfg=SDL_PATH specify path to sdl-config for local install [$sdl_path] + --enable-sdl-static use static SDL linking [default=no] + --X11-path=X11_PATH specify path for X11 includes and libraries [$X11_PATH] + --dxsdk-path=DX_PATH specify directX SDK for MinGW [$dxsdk_path] + --xulsdk-path=XUL_PATH specify Mozilla XUL (Gecko) SDK include path [$xulsdk_path] + --mozdir=MOZ_PATH specify mozilla main directory path for system install + --extra-ff-ldflags=ELDFLAGS add ELDFLAGS to FFMPEG LDFLAGS [$ffmpeg_extra_ldflags] + + --enable-debug produce debug version + --enable-gprof enable profiling + --enable-gcov enable coverage + --enable-pic enable Position Independant Code for shared objects + --strip enable strip + --std-allocator uses standard lib memory allocator + --static-modules includes static modules in libgpac whenever possible + --enable-mem-track enable tracking of all memory allocated by gpac + --disable-opt disable GCC optimizations + --disable-ipv6 disable IPV6 support + --disable-wx disable wxWidgets support + --disable-platinum disable Platinum UPnP support + --disable-alsa disable Alsa audio + --disable-oss-audio disable OSS audio + --enable-jack enable Jack audio + --disable-jack disable Jack audio + --enable-pulseaudio enable Pulse audio + --disable-pulseaudio disable Pulse audio + --disable-x11-shm disable X11 shared memory support + --disable-x11-xv disable X11 Xvideo support + --enable-fixed-point enable fixed-point math + --enable-tinygl enable TinyGL support + --enable-joystick enable joystick support + --disable-ssl disable OpenSSL support + --enable-amr-nb-fixed enable AMR NB fixed-point decoder + --enable-amr-nb enable AMR NB library + --enable-amr-wb enable AMR WB library + --enable-amr enable both AMR NB and WB libraries + --enable-static-bin link statically against libgpac + --static-mp4box configure for static linking of MP4Box only. + --enable-depth enables depth handling in the compositor + +Configuration options for libgpac - all options can be enabled with --enable-optname + --disable-all disables all features in libgpac + --disable-3d disable 3D rendering + --disable-svg disable SVG + --disable-vrml disable MPEG-4/VRML/X3D + --disable-x3d disable X3D only + --disable-odf disable full support of MPEG-4 OD Framework + --disable-bifs disable BIFS + --disable-bifs-enc disable BIFS coder + --disable-laser disable LASeR coder + --disable-saf disable SAF container + --disable-seng disable scene encoder engine + --disable-qtvr disable import of Cubic QTVR files + --disable-avi disable AVI + --disable-ogg disable OGG + --disable-m2ps disable MPEG2 PS + --disable-m2ts disable MPEG2 TS + --disable-m2ts-mux disable MPEG2 TS Multiplexer + --disable-dvb4linux disable dvb4linux support + --disable-parsers disable AV parsers + --disable-import disable media importers + --disable-export disable media exporters + --disable-swf disable SWF import + --disable-scene-stats disable scene graph statistics + --disable-scene-dump disable scene graph dump + --disable-scene-encode disable BIFS & LASeR to ISO File Format encoding + --disable-loader-isoff disable scene loading from ISO File Format + --disable-loader-bt disable scene loading from ISO File Format + --disable-loader-xmt disable scene loading from ISO File Format + --disable-od-dump disable OD dump + --disable-isom-dump disable ISOM dump + --disable-mcrypt disable mcrypt + --disable-isoff disable ISO File Format + --disable-isoff-write disable ISO File Format edit/write + --disable-isoff-hint disable ISO File Format hinting + --disable-isoff-frag disable fragments in ISO File Format + --disable-isoff-hds disable HDS support in ISO File Format + --disable-streaming disable RTP/RTSP/SDP + --disable-dvbx disable DVB-specific tools (MPE, FEC, DSM-CC) + --disable-vobsub disable VobSub support + --disable-sman disable scene manager + --disable-ttxt disable TTXT (3GPP / MPEG-4 Timed Text) support + --disable-player disable player (terminal and compositor) + --disable-scenegraph disable scenegraph, scene parsers and player (terminal and compositor) + --disable-hevc disable HEVC support + +Extra libraries configuration. You can turn a libray off or force using the local version in gpac/extra_lib/ + --use-js=OPT force SpiderMonkey ECMAScript OPT=[no,local] + --use-ft=OPT force FreeType OPT=[no,local] + --use-zlib=OPT force ZLIB OPT=[no,system,local] + --use-jpeg=OPT force JPEG OPT=[no,local] + --use-png=OPT force PNG OPT=[no,local] + --use-faad=OPT force FAAD OPT=[no,local] + --use-mad=OPT force MAD OPT=[no,local] + --use-xvid=OPT force XVID OPT=[no,local] + --use-ffmpeg=OPT force FFMPEG OPT=[no,local] + --use-ogg=OPT force OGG OPT=[no,system,local] + --use-vorbis=OPT force vorbis OPT=[no,system,local] + --use-theora=OPT force theora OPT=[no,system,local] + --use-openjpeg=OPT force openjpeg OPT=[no,system,local] + --use-a52=OPT force a52 (ac3) OPT=[no,system,local] + +NOTE: The object files are build at the place where configure is launched +EOF +exit 1 +fi + +for opt do + case "$opt" in + --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` + ;; + --libdir=*) libdir=`echo $opt | cut -d '=' -f 2` + ;; + --mandir=*) mandir=`echo $opt | cut -d '=' -f 2` + ;; + --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` && echo "cross-prefix detected: $cross_prefix" + ;; + --target-os=*) targetos=`echo $opt | cut -d '=' -f 2` && echo "target-os detected: $targetos" + ;; + --cc=*) cc_orig=`echo $opt | cut -d '=' -f 2` + ;; + --cxx=*) cxx_orig=`echo $opt | cut -d '=' -f 2` + ;; + --cpp=*) cxx_orig=`echo $opt | cut -d '=' -f 2` + ;; + --make=*) make=`echo $opt | cut -d '=' -f 2` + ;; + --extra-cflags=*) CFLAGS="$CFLAGS ${opt#--extra-cflags=}" + ;; + --extra-ldflags=*) LDFLAGS="$LDFLAGS ${opt#--extra-ldflags=}" + ;; + --extra-ff-ldflags=*) ffmpeg_extra_ldflags=`echo $opt | cut -d '=' -f 2` + ;; + --extra-libs=*) extralibs=${opt#--extra-libs=} + ;; + --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` + ;; + --enable-debug) debuginfo="yes"; no_gcc_opt="yes" + ;; + --disable-opt) no_gcc_opt="yes" + ;; + --enable-pic) want_pic="yes"; + ;; + --enable-gcov) want_gcov="yes"; + ;; + --verbose) verbose="yes"; + ;; + esac +done + + +cc="${cc_orig}" +cxx="${cxx_orig}" + +case "$cpu" in + i386|i486|i586|i686|i86pc|BePC) + cpu="x86" + ;; + x86_64|amd64) + cpu="x86" + if [ "$linux" = "yes" -o "$darwin" = "yes" ] ; then + is_64="yes" + fi + case `uname -s` in + SunOS) + canon_arch=`isainfo -n` + ;; + Darwin) + canon_arch="x86_64" + ;; + *) + canon_arch="`$cc -dumpmachine | sed -e 's,\([^-]*\)-.*,\1,'`" + ;; + esac + + if [ x"$canon_arch" = x"x86_64" -o x"$canon_arch" = x"amd64" ]; then + if [ -z "`echo $CFLAGS | grep -- -m32`" ]; then + cpu="x86_64" + want_pic="yes" + is_64="yes" + fi + fi + ;; + armv4l|arm) + cpu="armv4l" + ;; + alpha) + cpu="alpha" + ;; + ppc64) + cpu="powerpc" + ;; + "Power Macintosh"|ppc) + cpu="powerpc" + ;; + mips) + cpu="mips" + ;; + sh4|sh4a|sh) + cpu="sh4" + ;; + sun4u|sun4v) + cpu="sparc" + if [ -z "`echo $CFLAGS | grep -- -m32`" ]; then + is_64="yes" + PIC_CFLAGS="-fPIC -DPIC" + want_pic="yes" + fi + ;; + *) + cpu="unknown" + ;; +esac + +#checking for CFLAGS +if test -z "$CFLAGS"; then + CFLAGS="" +fi + + +cc="${cross_prefix}${cc}" +#for ccache +cc="${cc}" +cxx="${cross_prefix}${cxx}" +ar="${cross_prefix}${ar}" +ranlib="${cross_prefix}${ranlib}" +strip="${cross_prefix}${strip}" +pkg_config="${pkg_config}" +windres="${cross_prefix}${windres}" + + +#check pkg_config +if test "$cross_prefix" = "" ; then + if ! $pkg_config --version >/dev/null 2>>$logs ; then + pkg_config="no" + fi +fi + + +#find source path +source_path="`echo $0 | sed -e 's#/configure##'`" +source_path_used="yes" +if test -z "$source_path" -o "$source_path" = "." ; then + source_path="`pwd`" + source_path_used="no" + build_path=$source_path +else + source_path="`cd \"$source_path\"; pwd`" + build_path="`pwd`" +fi + + +#OS specific +if test "$targetos" = "" ; then + targetos=`uname -s` +fi +case $targetos in + BeOS) + js_flags=-DXP_BEOS + xul_flags=-DXP_BEOS + prefix="/boot/home/config" + CFLAGS="$CFLAGS -DPIC -fomit-frame-pointer" + # 3 gcc releases known for BeOS, each with ugly bugs + gcc_version="$($cc -v 2>>$logs | grep version | cut -d ' ' -f3-)" + case "$gcc_version" in + 2.9-beos-991026*|2.9-beos-000224*) echo "R5/GG gcc" + ;; + *20010315*) echo "BeBits gcc" + CFLAGS="$CFLAGS -fno-expensive-optimizations" + ;; + esac + + SHFLAGS=-nostart + #no need for libm, but the inet stuff + #check for BONE + if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then + extralibs="-lbind -lsocket" + else + need_inet_aton="yes" + extralibs="-lnet" + fi + ;; + + SunOS) + make="gmake" + readelf="greadelf" + LDFLAGS="$LDFLAGS" + instflags="" + #check for 64-bit + cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + CFLAGS_NO_LTO=$(echo ${CFLAGS} | sed -e 's/\ -flto[-A-Za-z0-9=]*//g') + $cc ${CFLAGS_NO_LTO} -o $TMPO $TMPC 2>>$logs && $($readelf -h $TMPO | grep "Class:.*ELF64$" >/dev/null 2>>$logs) + if test $? -eq 0; then + is_64="yes" + fi + if test "$is_64" = "yes"; then + if test "$cpu" = "x86_64"; then + libdir=lib/amd64 + elif test "$cpu" = "sparc"; then + libdir=lib/sparcv9 + fi + fi + sunos="yes" + need_inet_aton="yes" + extralibs="$extralibs -lsocket -lnsl" + ;; + + FreeBSD) + make="gmake" + LDFLAGS="$LDFLAGS -export-dynamic" + CFLAGS="$CFLAGS -pthread" + GPAC_SH_FLAGS=-pthread + freebsd="yes" + js_flags="-DXP_UNIX -I/usr/include/js" + ;; + + BSD/OS) + extralibs="-lpoll -lgnugetopt -lm" + make="gmake" + ;; + + Darwin) + js_flags=-DXP_MAC + xul_flags=-DXP_MAC + if test -d /sw/bin ; then + alt_macosx_dir="/sw" + CFLAGS_DIR="-I/sw/include" + LDFLAGS="-L/sw/lib $LDFLAGS" + elif test -d /opt/local/bin ; then + alt_macosx_dir="/opt/local" + CFLAGS_DIR="-I/opt/local/include" + LDFLAGS="-L/opt/local/lib $LDFLAGS" + fi + cc="cc" + Mac_Applications="/Applications" + SHFLAGS="-dynamiclib" + DYN_LIB_SUFFIX=".dylib" + extralibs="" + GPAC_SH_FLAGS="" + strip="strip -x" + if test "$is_64" = "yes" ; then + LDFLAGS="$LDFLAGS" + fi + darwin="yes" + gcc_version=`$cc -v 2>>$logs | grep version | cut -d ' ' -f3` + case "$gcc_version" in + *2.95*) + CFLAGS="$CFLAGS -no-cpp-precomp -pipe -fomit-frame-pointer" + ;; + 3.*) + CFLAGS="$CFLAGS -no-cpp-precomp -pipe -fomit-frame-pointer -mdynamic-no-pic -fno-common" + ;; + 4.*) + CFLAGS="$CFLAGS -pipe -fomit-frame-pointer -fno-common" + ;; + esac + ;; + + MINGW32*|mingw32|MINGW64*|mingw64) + js_flags="-DXP_PC -D_declspec=__declspec" + mingw32="yes" + win32="yes" + want_pic="no" + extralibs="$extralibs -lws2_32 -lwinmm" + CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" + if test "$cross_prefix" != "" ; then + GPAC_SH_FLAGS="" + fi + ;; + + CYGWIN*|cygwin*) + js_flags=-DXP_PC + extralibs="$extralibs -lws2_32 -lwinmm" + cygwin="yes" + win32="yes" + ;; + + Linux|linux|android) + js_flags="-DXP_UNIX -I/usr/include/js" + LDFLAGS="$LDFLAGS -Wl,--warn-common -Wl,-z,defs" + linux="yes" + case "$cpu" in + sh4) + CFLAGS="$CFLAGS -isystem \"$prefix/include\"" + ;; + esac + cat > $TMPC << EOF +#include +#if !defined (__BIONIC__) +#error +#endif +EOF + if $cc -c $CFLAGS $TMPC 0>/dev/null 2>$TMPL ; then + #bionic libc (android) + CFLAGS="$CFLAGS -DPTHREAD_HAS_NO_CANCEL" + GPAC_SH_FLAGS="" + fi + ;; + + *) ;; +esac + + +#defines directory for binaries and libs (ex. for TinyGL) +target_bin_dir="" +if test "$cross_prefix" = "" ; then + target_bin_dir=`${cc} -v 2>>$logs | sed -n '2p' | awk ' {print $2}'`-${cc_orig} +else + target_bin_dir=${cross_prefix}${cc_orig} +fi + + +#if test "$source_path_used" = "yes" ; then +mkdir -p extra_lib +mkdir -p extra_lib/lib +mkdir -p extra_lib/lib/gcc +#fi + + +#OK check for all local & systems lib +local_inc=$source_path/extra_lib/include +local_lib=extra_lib/lib/gcc + + +dolog() { + rv=$? + if [ $rv -eq 0 ] ; then + return 0; + fi + + echo "*** CC/CXX Test Failed (args $@) : ">>$logs + echo "">>$logs + cat $TMPL >> $logs + echo "">>$logs + echo "Source was: ">>$logs + cat $TMPC >> $logs + echo "">>$logs + echo "">>$logs + return 1; +} + +docc() { + $cc -o $TMPO $TMPC $@ 0>/dev/null 2>$TMPL + dolog $@ +} + + +docxx() { + $cc -o $TMPO $TMPC $@ 0>/dev/null 2>$TMPL + dolog $@ +} + +#check GCC flags support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF +CFLAGS="$CFLAGS -Wall" +if docc -fno-strict-aliasing ; then + CFLAGS="$CFLAGS -fno-strict-aliasing" +fi +CXXFLAGS="$CFLAGS" +if docc -lz -Wno-pointer-sign ; then + CFLAGS="$CFLAGS -Wno-pointer-sign" +fi + + +#GCC opt +if test "$no_gcc_opt" = "no"; then + CFLAGS="-O3 $CFLAGS" +else + CFLAGS="-O0 $CFLAGS" +fi + + +#GCC PIC +if test "$cross_prefix" != "" ; then + want_pic="no" +fi +if test "$want_pic" = "yes" ; then + CFLAGS="$CFLAGS -fPIC -DPIC" + CXXFLAGS="$CXXFLAGS -fPIC -DPIC" +fi + +if test "$want_gcov" = "yes" ; then + CFLAGS="$CFLAGS --coverage" + CXXFLAGS="$CXXFLAGS --coverage" + LDFLAGS="$LDFLAGS --coverage" +fi + +#force use of cflags with cc +cc_naked=$cc +cxx_naked=$cxx +cc="$cc $CFLAGS" +cxx="$cxx $CXXFLAGS" + +#look for zlib +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc -msse2 $LDFLAGS ; then + CFLAGS="$CFLAGS -msse2" +fi + + +#look for zlib +cat > $TMPC << EOF +#include +#include +#include +int main( void ) { if (strcmp(zlibVersion(), ZLIB_VERSION)) { puts("zlib version differs !!!"); return 1; } return 0; } +EOF +has_zlib="no" +if docc -lz $LDFLAGS ; then + has_zlib="system" +fi +if test "$has_zlib" = "no" ; then + if docc -I"$local_inc/zlib" -L$local_lib -lz ; then + has_zlib="local" + fi +fi + +#check dlopen +cat > $TMPC << EOF +#include +int main( void ) { dlopen("foo", 0); return 0; } +EOF + +if docc ; then + dlopen="yes" +elif docc $LDFLAGS -ldl ; then + GPAC_SH_FLAGS="$GPAC_SH_FLAGS -ldl" +fi + + + +#look for spidermonkey JS support +mozjs_pkgcfg="no" + + +#spidermonkey test for new API +if test "$has_js" = "no" ; then + +cat > $TMPC << EOF +#include +int main( void ) { JSContext *cx=NULL; jsval rp; return JS_AddValueRoot(cx, &rp); } +EOF + + #try local + js_inc="$local_inc/js" + js_flags="-DXP_UNIX -I$local_inc/js" + if docc $js_flags -L$local_lib -ljs -lpthread ; then + has_js="local" + #dc added + elif test "$pkg_config" != "no"; then + #try pkg-config + if $pkg_config --exists mozilla-js ; then + mozjs_pkgcfg="mozilla-js" + elif $pkg_config --exists mozjs ; then + mozjs_pkgcfg="mozjs" + elif $pkg_config --exists mozjs185 ; then + mozjs_pkgcfg="mozjs185" + fi + + if test $mozjs_pkgcfg != "no" ; then + js_flags=`$pkg_config --cflags $mozjs_pkgcfg` + js_lib_pkg=`$pkg_config --libs $mozjs_pkgcfg` + if docc $js_flags $js_lib_pkg $LDFLAGS -lpthread ; then + has_js="system" + js_lib=`$pkg_config --libs $mozjs_pkgcfg` + fi + #try firefox folders (starting at ubuntu 11.10, no pkg-config) + elif ls -d /usr/lib/firefox* > /dev/null 2>>$logs ; then + firefox_version=`cd /usr/lib ; ls -d firefox* | grep -v addons | grep -v devel ; cd - > /dev/null` + for i in $firefox_version ; do + if test "$has_js" = "no" ; then + js_inc="/usr/include/$i" + js_flags="-DXP_UNIX -I$js_inc" + js_lib="-L/usr/lib/$i/ -lxul -lmozsqlite3 -lmozalloc -lnssutil3 -lnss3 -lnspr4 -lsmime3" + if docc $js_flags $js_lib ; then + has_js="$i" + elif docc $js_flags -lnssutil3 $js_lib -lssl3 ; then + #firefox 11 compatibility + has_js="$i" + js_lib="-lnssutil3 $js_lib -lssl3" + fi + fi + done + fi + + if test "$has_js" = "no" ; then + #try prefix (DC) + js_inc="$prefix/include/js" + js_flags="-DXP_UNIX -I$prefix/include/js" + if docc $js_flags -L$prefix/lib -ljs -lpthread ; then + has_js="prefix" + #dc added end + else + if docc $js_flags $LDFLAGS -ljs -lpthread ; then + js_inc="/usr/include" + has_js="system" + elif docc -DXP_UNIX -I$alt_macosx_dir/include/js -L$alt_macosx_dir/lib $LDFLAGS -ljs -lpthread 2>>$logs ; then + has_js="system" + js_flags="-DXP_UNIX -I$alt_macosx_dir/include/js" + js_lib="-L$alt_macosx_dir/lib -ljs" + js_inc="$alt_macosx_dir/include/js" + else + #debian spidermonkey (smjs) + js_flags="-DXP_UNIX -I/usr/include/smjs" + js_inc="/usr/include/smjs" + if docc $js_flags $LDFLAGS -lsmjs -lpthread ; then + has_js="system" + js_lib="-lsmjs" + else + #debian spidermonkey (mozjs) + js_flags="-DXP_UNIX -I/usr/include/mozjs" + js_inc="/usr/include/mozjs" + if docc $js_flags $LDFLAGS -lmozjs -lpthread ; then + has_js="system" + js_lib="-lmozjs" + fi + fi + fi + fi + fi + fi +fi + +new_js_api="no" +if test "$has_js" != "no" ; then + js_flags="-DSPIDERMONKEY_NEW_API $js_flags" + new_js_api="yes" +fi + +#spidermonkey test for regular API +if test "$has_js" = "no" ; then + +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + + #try local + js_inc="$local_inc/js" + js_flags="-DXP_UNIX -I$local_inc/js" + if test "$cpu" = "sh4" ; then + lm_lib="-lm" + fi + if docc $js_flags $lm_lib -L$local_lib -ljs ; then + has_js="local" + #dc added + else + #try prefix (DC) + js_inc="$prefix/include/js" + js_flags="-DXP_UNIX -I$prefix/include/js" + if docc $js_flags -L$prefix/lib -ljs ; then + has_js="prefix" + #dc added end + elif test "$pkg_config" != "no"; then + if $pkg_config --exists mozilla-js ; then + mozjs_pkgcfg="mozilla-js" + elif $pkg_config --exists mozjs ; then + mozjs_pkgcfg="mozjs" + elif $pkg_config --exists mozjs185 ; then + mozjs_pkgcfg="mozjs185" + fi + + if test $mozjs_pkgcfg != "no" ; then + js_flags=`$pkg_config --cflags $mozjs_pkgcfg` + js_lib_pkg=`$pkg_config --libs $mozjs_pkgcfg` + if docc $js_flags $js_lib_pkg $LDFLAGS -lpthread ; then + has_js="system" + js_lib=`$pkg_config --libs $mozjs_pkgcfg` + fi + fi + fi + if test "$has_js" = "no" ; then + if docc $js_flags $LDFLAGS -ljs ; then + js_inc="/usr/include" + has_js="system" + elif docc -DXP_UNIX -I$alt_macosx_dir/include/js -L$alt_macosx_dir/lib $LDFLAGS -ljs 2>>$logs ; then + has_js="system" + js_flags="-DXP_UNIX -I$alt_macosx_dir/include/js" + js_lib="-L$alt_macosx_dir/lib -ljs" + js_inc="$alt_macosx_dir/include/js" + else + #debian spidermonkey (smjs) + js_flags="-DXP_UNIX -I/usr/include/smjs" + js_inc="/usr/include/smjs" + if docc $js_flags $LDFLAGS -lsmjs ; then + has_js="system" + js_lib="-lsmjs" + else + #debian spidermonkey (mozjs) + js_flags="-DXP_UNIX -I/usr/include/mozjs" + js_inc="/usr/include/mozjs" + if docc $js_flags $LDFLAGS -lmozjs ; then + has_js="system" + js_lib="-lmozjs" + fi + fi + fi + fi + fi +fi + +if test "$has_js" != "no" ; then + if test "$linux" = "yes" ; then + if test "$cpu" != "sh4"; then + #WARNING: there is a bug in MOZJS packages, the MOZILLA_1_8_BRANCH macro is not signaled, there is no way of knowing + #if the lib has been compiled with or without the macro. We currently just decide that if the macro is present + #in the header, it was enabled in the build + if test "$new_js_api" = "no" ; then + if grep MOZILLA_1_8_BRANCH $js_inc/jsapi.h > /dev/null 2>>$logs ; then + js_flags="-DMOZILLA_1_8_BRANCH $js_flags" + echo "WARNING: Turning on MOZILLA_1_8_BRANCH SpiderMonkey macro" + echo "If you have troubles with scripts in GPAC, disable this macro and recompile" + fi + else + +cat > $TMPC << EOF +#include +int main( void ) { JSObject *obj; JS_GetPrivate(obj); return 0; } +EOF + if docc $js_flags $LDFLAGS $js_lib ; then + +cat > $TMPC << EOF +#include +int main( void ) { jsval vp; JSContext *cx=NULL; JSObject *obj = JS_NewObjectForConstructor(cx, &vp); return 0; } +EOF + if docc $js_flags $LDFLAGS $js_lib ; then + js_flags="-DUSE_FFDEV_12 $js_flags" + elif grep JSMutableHandleValue $js_inc/jsapi.h | grep JSHasInstanceOp > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_18 $js_flags" + elif grep JSMutableHandleValue $js_inc/jsapi.h > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_18 $js_flags" + elif ! grep JS_ConstructObject $js_inc/jsapi.h > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_16 $js_flags" + elif grep JSHandleObject $js_inc/jsapi.h > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_15 $js_flags" + else + js_flags="-DUSE_FFDEV_14 $js_flags" + fi + fi + fi + fi + fi +fi + + + +if test "$has_js" != "no" ; then +cat > $TMPC << EOF +#include +int main( void ) { JSContext *cx=NULL; JS_SetRuntimeThread(cx); return 0;} +EOF + if docc $js_flags $LDFLAGS $js_lib ; then + js_flags="$js_flags" + else + js_flags="-DNO_JS_RUNTIMETHREAD $js_flags" + fi +fi + + +#end JS test + + + +#look for platinum support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF +if docxx -o $TMPO $TMPC -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib -lpthread ; then + has_platinum="yes" +fi + + +#look for avcap support +avcap_cflags="" +avcap_ldflags="-lavcap" + +cat > $TMPC << EOF +#include +using namespace avcap; +int main( void ) { + const DeviceCollector::DeviceList& dl = DEVICE_COLLECTOR::instance().getDeviceList(); + DeviceDescriptor* dd = 0; + for (DeviceCollector::DeviceList::const_iterator i = dl.begin(); i != dl.end(); i++) { + dd = *i; + std::cout << dd->getName().c_str() << "\n"; + } + return 0; +} +EOF +if docxx -o $TMPO $TMPC $LDFLAGS $avcap_cflags $avcap_ldflags ; then + has_avcap="yes" +else + if test "$darwin" = "yes" ; then + avcap_cflags="-I$local_inc -I$local_inc/avcap/osx" + avcap_ldflags="${wl}-flat_namespace -lavcap -lpthread -framework QuickTime -framework QuartzCore" + else + avcap_cflags="-I$local_inc -I$local_inc/avcap/linux" + avcap_ldflags="-lavcap -lpthread" + fi + if docxx -o $TMPO $TMPC $avcap_cflags $LDFLAGS -L$local_lib $avcap_ldflags ; then + has_avcap="yes" + avcap_ldflags="-L../../$local_lib $avcap_ldflags" + fi +fi + + +#look for opensvc support + +if test "$darwin" = "yes" ; then + osvc_cflags="-I/usr/include -I/usr/local/include" + osvc_ldflags="-L/usr/lib -L/usr/local/lib -lOpenSVCDec" +else + osvc_cflags="" + osvc_ldflags="-lOpenSVCDec" +fi + +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF +if docc $osvc_cflags $LDFLAGS $osvc_ldflags ; then + has_opensvc="yes" +else +osvc_cflags="-I$local_inc" +osvc_ldflags="-lOpenSVCDec" + +if docc $osvc_cflags $LDFLAGS -L$local_lib $osvc_ldflags ; then + has_opensvc="yes" + osvc_ldflags="-L../../$local_lib $osvc_ldflags" +fi + +fi + +#look for openhevc support + +if test "$darwin" = "yes" ; then + ohevc_cflags="-I/usr/include -I/usr/local/include" + ohevc_ldflags="-L/usr/lib -L/usr/local/lib -lLibOpenHevcWrapper -lm -lpthread " +elif test "$cross_prefix" = "" ; then + ohevc_cflags="" + ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" +else + ohevc_cflags="-I${prefix}include" + ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" +fi + +cat > $TMPC << EOF +#include +#include +int main( void ) { libOpenHevcInit(1, 1); return 0; } +EOF +if docc $ohevc_cflags $ohevc_ldflags $LDFLAGS ; then + has_openhevc="yes" +else + ohevc_cflags="-I$local_inc" + ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" + if docc $ohevc_cflags $ohevc_ldflags $LDFLAGS -L$local_lib ; then + has_openhevc="yes" + ohevc_ldflags="-L../../$local_lib $ohevc_ldflags" + fi +fi + + +#look for freetype support +cat > $TMPC << EOF +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_OUTLINE_H +int main( void ) { return 0; } +EOF +ft_cflags="-I$prefix/include " +ft_lflags="-L$prefix/lib -lfreetype" +if docc $CFLAGS_DIR $ft_cflags $ft_lflags $LDFLAGS ; then + has_ft="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_ft" = "no" ; then + ft_cflags="`freetype-config --cflags 2>>$logs`" + ft_lflags="`freetype-config --libs 2>>$logs`" + if docc $ft_cflags $ft_lflags $LDFLAGS ; then + has_ft="system" + fi + fi +fi +if test "$has_ft" = "no" ; then + if test "`which freetype-config 2>>$logs`" != ""; then + ft_cflags="-I$local_inc/freetype" + ft_lflags="-L$local_lib -lfreetype" + if docc $ft_cflags $ft_lflags ; then + has_ft="local" + fi + fi +fi +#end freetype test + + + +#look for OpenSSL support +cat > $TMPC << EOF +#include +#include +#include +#include +int main( void ) { return 0; } +EOF + +if test "$win32" = "yes" ; then + LINK_SSL="-lssleay32 -leay32" +else + LINK_SSL="-lssl -lcrypto" +fi + +if docc $LINK_SSL $LDFLAGS ; then + has_ssl="yes" +fi + + + +#look for JPEG support +cat > $TMPC << EOF +#include +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -ljpeg ; then + has_jpeg="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_jpeg" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ljpeg 2>>$logs ; then + has_jpeg="system" + fi + elif test "`which $prefix/bin/jpeg-config 2>>$logs`" != ""; then + jpeg_cflags="`$prefix/bin/jpeg-config --cflags`" + jpeg_lflags="`$prefix/bin/jpeg-config --libs`" + if docc $jpeg_cflags $jpeg_lflags $LDFLAGS ; then + has_jpeg="system" + fi + else + jpeg_cflags="-I$prefix/include" + jpeg_lflags="-L$prefix/lib -ljpeg" + if docc $jpeg_cflags $jpeg_lflags $LDFLAGS ; then + has_jpeg="system" + fi + fi + fi +fi +if test "$has_jpeg" = "no" ; then + jpeg_cflags="-I$local_inc/jpeg" + jpeg_lflags="-L$local_lib -ljpeg" + if docc $jpeg_cflags $jpeg_lflags ; then + has_jpeg="local" + fi +fi + + + +#look for OpenJPEG support +cat > $TMPC << EOF +#include +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -lopenjpeg ; then + has_openjpeg="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_openjpeg" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ljpeg 2>>$logs ; then + has_openjpeg="system" + fi + fi + fi +fi + +if test "$has_openjpeg" = "no" ; then + if docc -I$local_inc/openjpeg -L$local_lib -lopenjpeg ; then + has_openjpeg="local" + fi +fi + + + +#look for PNG support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +png_cflags="-I$prefix/include" +png_lflags="-L$prefix/lib -lpng -lz" +if docc $png_cflags $png_lflags $LDFLAGS ; then + has_png="system" +elif docc $LDFLAGS -lpng -lz ; then + has_png="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_png" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lpng 2>>$logs ; then + has_png="system" + fi + fi + fi +fi +if test "$has_png" = "no" ; then + if docc -I$local_inc/png -L$local_lib -lpng ; then + has_png="local" + fi +fi + + + +#look for MAD support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -lmad ; then + has_mad="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_mad" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lmad 2>>$logs ; then + has_mad="system" + fi + fi + fi +fi +if test "$has_mad" = "no" ; then + if docc -I$local_inc/mad -L$local_lib -lmad ; then + has_mad="local" + fi +fi + + + +#look for A52DEC support +cat > $TMPC << EOF +#include +#define uint32_t unsigned int +#define uint8_t unsigned char +#include +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -la52 ; then + has_a52="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_a52" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -la52 2>>$logs ; then + has_a52="system" + fi + fi + fi +fi +if test "$has_a52" = "no" ; then + if docc -I$local_inc -L$local_lib -la52 ; then + has_a52="local" + fi +fi + + + +#look for XVID support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc -I$prefix/include -L$prefix/lib $LDFLAGS -lxvidcore -lpthread ; then + has_xvid="system" +elif docc $LDFLAGS -lxvidcore -lpthread ; then + has_xvid="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_xvid" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lxvidcore -lpthread 2>>$logs ; then + has_xvid="system" + fi + fi + fi +fi +if test "$has_xvid" = "no" ; then + if docc -I$local_inc/xvid -L$local_lib -lxvidcore -lpthread ; then + has_xvid="local" + fi +fi + + + +#look for FAAD support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -lfaad -lm ; then + has_faad="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_faad" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lfaad 2>>$logs ; then + has_faad="system" + fi + fi + fi +fi +if test "$has_faad" = "no" ; then + if docc -I$local_inc/faad -L$local_lib -lfaad -lm ; then + has_faad="local" + fi +fi + + + +#look for FFMPEG support + +ffmpeg_cflags="" +ffmpeg_lflags="-lz -lavcodec -lavformat -lavutil -lswscale -lavdevice $ffmpeg_extra_ldflags" + +if test "$cross_prefix" = "" -a "$pkg_config" != "no"; then + if $pkg_config --exists libavcodec libavformat libswscale libavdevice libavutil ; then + ffmpeg_cflags=`$pkg_config --cflags libavcodec libavformat libswscale libavutil libavdevice` + ffmpeg_lflags=`$pkg_config --libs libavcodec libavformat libswscale libavutil libavdevice` + has_ffmpeg="system" + fi +fi + +cat > $TMPC << EOF +#include +int main(void) { + return 0; +} +EOF + +if docc $ffmpeg_cflags $ffmpeg_lflags $LDFLAGS ; then + old_ffmpeg_inc="no" +else + old_ffmpeg_inc="yes" + +cat > $TMPC << EOF +#include +#include +int main(void) { + AVFrame *f1, *f2; + printf("ID %d", AV_CODEC_ID_H264); + f2 = av_frame_clone(f1); + return 0; +} +EOF + +fi + +cat > $TMPC << EOF +#include +#include +int main(void) { + printf("ID %d", CODEC_ID_H264); + return 0; +} +EOF + +if docc -I$prefix/include -L$prefix/lib $ffmpeg_lflags $LDFLAGS ; then + has_ffmpeg="system" + ffmpeg_cflags="-I$prefix/include" + ffmpeg_lflags="-L$prefix/lib $ffmpeg_lflags" +elif docc $ffmpeg_lflags $LDFLAGS ; then + has_ffmpeg="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_ffmpeg" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $ffmpeg_lflags $LDFLAGS 2>>$logs ; then + has_ffmpeg="system" + ffmpeg_cflags="-I$alt_macosx_dir/include" + ffmpeg_lflags="-L$alt_macosx_dir/lib $ffmpeg_lflags" + fi + fi + fi +fi +if test "$has_ffmpeg" = "no" ; then + if docc -I$local_inc -L$local_lib $ffmpeg_lflags ; then + has_ffmpeg="local" + ffmpeg_cflags="-I$local_inc" + ffmpeg_lflags="-L$local_lib $ffmpeg_lflags" + fi +fi + +cat > $TMPC << EOF +#include +#include +#include +int main(void) { + printf("ID %d", CODEC_ID_H264); + return 0; +} +EOF +if docc $ffmpeg_cflags $ffmpeg_lflags ; then + is_libav="no" +else + +cat > $TMPC << EOF +#include +int main(void) { + CODEC_ID_H264; + return 0; +} +EOF + + if docc $ffmpeg_cflags $ffmpeg_lflags ; then + is_libav="yes" + else + is_libav="new" + fi +fi + +#detect libavresample (libav only, but ffmpeg backported with '--enable-avresample') for dashcast only +cat > $TMPC << EOF +#include "libavresample/avresample.h" +int main(void) { + AVAudioResampleContext *aresampler = avresample_alloc_context(); + free(aresampler); + return 0; +} +EOF + +if docc $ffmpeg_cflags $ffmpeg_lflags -lavresample ; then + has_libavresample="yes" +else + has_libavresample="no" +fi + + +#look for FREENECT support +freenect_flags="" +freenect_ld="-lfreenect" +has_freenect="no" +if test "$pkg_config" != "no"; then + if $pkg_config --exists libfreenect ; then + freenect_flags=`$pkg_config --cflags libfreenect` + freenect_libs=`$pkg_config --libs libfreenect` + has_freenect="system" + freenect_flags="-DFREENECT_FLAT_HEADERS $freenect_flags" + fi +fi + +if test "$has_freenect" = "no"; then + +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -lfreenect ; then + has_freenect="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_freenect" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lfreenect 2>>$logs ; then + has_freenect="system" + freenect_flags=-I$alt_macosx_dir/include + freenect_ld=-L$alt_macosx_dir/lib -lfreenect + fi + fi + fi +fi +if test "$has_freenect" = "no" ; then + if docc -I$local_inc/freenect -L$local_lib -lfreenect ; then + has_freenect="local" + freenect_flags=-I$local_inc/freenect + freenect_ld=-L$local_lib -lfreenect + fi +fi + +fi + + +#look for vorbis support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -lvorbis ; then + has_vorbis="system" +elif test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lvorbis 2>>$logs ; then + has_vorbis="system" + fi +elif docc -I$local_inc -L$local_lib -lvorbis -lm ; then + has_vorbis="local" +fi + + + +#look for theora support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -ltheora ; then + has_theora="system" +elif test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ltheora -logg 2>>$logs ; then + has_theora="system" + fi +elif docc -I$local_inc -L$local_lib -ltheora -logg -lm ; then + has_theora="local" +fi + + + +#look for OGG support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -logg ; then + has_ogg="system" +elif test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -logg 2>>$logs ; then + has_ogg="system" + fi +elif docc -I$local_inc -L$local_lib -logg -lm ; then + has_ogg="local" +else + has_vorbis=no + has_theora=no +fi + + + +#look for OSS support +if test "$darwin" = "yes" ; then + + cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + + if docc -DLIBOSS_INTERNAL -I$alt_macosx_dir/include/ -I$alt_macosx_dir/include/liboss -L$alt_macosx_dir/lib -loss $LDFLAGS 2>>$logs ; then + has_oss_audio="yes" + OSS_CFLAGS="-DLIBOSS_INTERNAL -I$alt_macosx_dir/include/ -I$alt_macosx_dir/include/liboss" + OSS_LDFLAGS="-L$alt_macosx_dir/lib -loss" + fi + +else + + cat > $TMPC << EOF +#include +#include +#include +#include +int main( void ) { return 0; } +EOF + + if docc ; then + has_oss_audio="yes" + else + cat > $TMPC << EOF +#include +#include +#include +#include +int main( void ) { return 0; } +EOF + + if docc $LDFLAGS ; then + has_oss_audio="yes" + fi + fi + +fi + + + +#look for wxWidgets support +has_wx="no" +wx_too_old="no" + +if test "$cross_prefix" = "" ; then + if type wx-config >/dev/null 2>>$logs; then + + wx_version=`wx-config --version | sed 's/[^0-9]//g'` + + if test "$wx_version" -lt 250 ; then + wx_too_old="yes" + has_wx="yes" + else + if test "$wx_version" -lt 260 ; then + has_wx="yes" + wx_cflags=`wx-config --cppflags` + wx_lflags=`wx-config --libs` + else + has_wx="yes" + wx_cflags=`wx-config --cppflags core, base` + wx_lflags=`wx-config --libs core, base` + fi + + if test "$darwin" = "yes" ; then + wx_lflags="-Wl,-bind_at_load $wx_lflags -lstdc++" #10.4 needs it, not sure about 10.3 + fi + fi + + cat > $TMPCXX << EOF +#include +int main( void ) { return 0; } +EOF + + if $cc $wx_cflags -o $TMPO $TMPCXX $wx_lflags > /dev/null 2>>$logs ; then + wx_version=`wx-config --version | sed 's/[^0-9]//g'` + if test "$wx_version" -lt 254 ; then + wx_too_old="yes" + else + has_wx="yes" + fi + fi + fi +fi +#end wx test + +#look for IPv6 +cat > $TMPC << EOF +#include +#include +#include +#include +#include +int main( void ) { +struct sockaddr_storage saddr; +struct ipv6_mreq mreq6; +getaddrinfo(0,0,0,0); +getnameinfo(0,0,0,0,0,0,0); +memset(&saddr, 0, sizeof(saddr)); +memset(&mreq6, 0, sizeof(mreq6)); +IN6_IS_ADDR_MULTICAST( (struct in6_addr *) 0); +return 0; +} +EOF + +if docc $LDFLAGS $extralibs ; then + has_ipv6="yes" +fi + + + +#look for DVB4linux +cat > $TMPC << EOF +#include +#include +int main( void ) { +} +EOF + +if docc $LDFLAGS ; then + has_dvb4linux="yes" +fi + + + +#look for XMLRPC +cat > $TMPC << EOF +#include +#include +#include +int main( void ) { +return 0; +} +EOF + +if docc $LDFLAGS ; then + has_xmlrpc="yes" +fi + + + +#look for alsa +cat > $TMPC << EOF +#include +int main( void ) { +return 0; +} +EOF + +if docc $LDFLAGS ; then + has_alsa="yes" +fi + + + +#look for pulseaudio +cat > $TMPC << EOF +#include +int main( void ) { +return 0; +} +EOF + +if docc $LDFLAGS ; then + has_pulseaudio="yes" +fi + + + +#look for jack +cat > $TMPC << EOF +#include +int main( void ) { +return 0; +} +EOF +if docc $LDFLAGS ; then + has_jack="yes" +fi + + + +#look for directfb support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF +directfb_inc="/usr/include/directfb" +directfb_lib="-ldirectfb -lfusion -ldirect" +if docc -I$directfb_inc -L$directfb_lib $LDFLAGS ; then + has_directfb="yes" +fi + + + +#look for X11 shared memory support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + +if docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then + has_x11="yes" + + #look for X11 shared memory support + cat > $TMPC << EOF +#include +#include +#include +#include +int main( void ) { return 0; } +EOF + + if docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then + has_x11_shm="yes" + fi + + #look for XVideo support + cat > $TMPC << EOF +#include +#include +#include +int main( void ) { return 0; } +EOF + + if docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then + has_x11_xv="yes" + fi + +fi + + + +#overwrite detection with manual settings +for opt do + case "$opt" in + --static-modules) static_modules="yes" + ;; + --sdl-cfg=*) sdl_path=`echo $opt | cut -d '=' -f 2`; sdl_local="yes" + ;; + --enable-sdl-static=*) sdl_static="yes" + ;; + --enable-jack) has_jack="yes" + ;; + --X11-path=*) X11_PATH=`echo $opt | cut -d '=' -f 2` + ;; + --dxsdk-path=*) dxsdk_path=`echo $opt | cut -d '=' -f 2` + ;; + --xulsdk-path=*) xulsdk_path=`echo $opt | cut -d '=' -f 2` + ;; + --mozdir=*) moz_path=`echo $opt | cut -d '=' -f 2` + ;; + --enable-amr-nb-fixed) has_amr_nb_fixed="yes" + ;; + --disable-pulseaudio) has_pulseaudio="no" + ;; + --enable-amr-nb) has_amr_nb="yes" + ;; + --enable-amr-wb) has_amr_wb="yes" + ;; + --enable-amr) has_amr_wb="yes"; has_amr_nb="yes" + ;; + --disable-oggvorbis) has_oggvorbis="no" + ;; + --disable-jack) has_jack="no" + ;; + --disable-alsa) has_alsa="no" + ;; + --enable-gprof) gprof_build="yes"; + ;; + --enable-static-bin) static_build="yes"; + ;; + --disable-ipv6) has_ipv6="no" + ;; + --disable-wx) has_wx="no" + ;; + --disable-platinum) has_platinum="no" + ;; + --disable-oss-audio) has_oss_audio="no" + ;; + --disable-x11-shm) has_x11_shm="no" + ;; + --disable-x11-xv) has_x11_xv="no" + ;; + --enable-fixed-point) use_fixed_point="yes" + ;; + --strip) INSTFLAGS="-s $INSTFLAGS" + ;; + --enable-mem-track) use_memory_tracking="yes" + ;; + --enable-tinygl) enable_tinygl="yes" + ;; + --disable-ssl) has_ssl="no" + ;; + --enable-depth) enable_depth_compositor="yes" + ;; + --static-mp4box) static_mp4box="yes" + ;; + --use-faad=*) has_faad=${opt#--use-faad=} + ;; + --use-js=*) has_js=${opt#--use-js=} + ;; + --use-ft=*) has_ft=${opt#--use-ft=} + ;; + --use-mad=*) has_mad=${opt#--use-mad=} + ;; + --use-a52=*) has_a52=${opt#--use-a52=} + ;; + --use-xvid=*) has_xvid=${opt#--use-xvid=} + ;; + --use-jpeg=*) has_jpeg=${opt#--use-jpeg=} + ;; + --use-ffmpeg=*) has_ffmpeg=${opt#--use-ffmpeg=} + ;; + --use-freenect=*) has_freenect=${opt#--use-freenect=} + ;; + --use-png=*) tmp_has_png=${opt#--use-png=} + if test "$tmp_has_png" = "system" ; then + if test "$has_png" != "system" ; then + if test "$cross_prefix" != "" ; then + echo + echo "WARNING: PNG has been forced to system, but we are cross-compiling, it will have to be on target" + echo + else + echo + echo "WARNING!! : PNG has been forced to system even though it hasn't been found in this host" + echo + fi + fi + fi + has_png=$tmp_has_png + ;; + --use-zlib=*) tmp_has_zlib=${opt#--use-zlib=} + if test "$tmp_has_zlib" = "system" ; then + if test "$has_zlib" != "system" ; then + if test "$cross_prefix" != "" ; then + echo + echo "WARNING: ZLIB has been forced to system, but we are cross-compiling, it will have to be on target" + echo + else + echo + echo "WARNING!! : ZLIB has been forced to system even though it hasn't been found in this host" + echo + fi + fi + has_zlib=$tmp_has_zlib + elif test "$tmp_has_zlib" = "no" ; then + echo + echo "WARNING!! : you have forced not to use ZLIB. This will disable some core functionalities of GPAC." + echo + has_zlib="force-no" + fi + ;; + --use-ogg=*) has_ogg=${opt#--use-ogg=} + ;; + --use-vorbis=*) has_vorbis=${opt#--use-vorbis=} + ;; + --use-theora=*) has_theora=${opt#--use-theora=} + ;; + --use-openjpeg=*) has_openjpeg=${opt#--use-openjpeg=} + ;; + --enable-joystick) enable_joystick="yes" + ;; + --enable-pulseaudio) has_pulseaudio="yes" + ;; + --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_mcrypt="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_ttml="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_isoff_hds="yes"; disable_hevc="yes" + ;; + --isomedia-only) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_mcrypt="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_hevc="no"; disable_isoff="no"; disable_isoff_hds="no"; disable_isoff_write="no"; disable_isoff_hint="no"; disable_isoff_frag="no" + ;; + --disable-3d) disable_3d="yes" + ;; + --enable-3d) disable_3d="no" + ;; + --disable-svg) disable_svg="yes" + ;; + --enable-svg) disable_svg="no" + ;; + --disable-vrml) disable_vrml="yes" + ;; + --enable-vrml) disable_vrml="no" + ;; + --disable-x3d) disable_x3d="yes" + ;; + --enable-x3d) disable_x3d="no" + ;; + --disable-odf) disable_od="yes" + ;; + --enable-odf) disable_od="no" + ;; + --disable-bifs) disable_bifs="yes" + ;; + --enable-bifs) disable_bifs="no" + ;; + --disable-bifs-enc) disable_bifs_enc="yes" + ;; + --enable-bifs-enc) disable_bifs_enc="no" + ;; + --disable-laser) disable_laser="yes" + ;; + --enable-laser) disable_laser="no" + ;; + --disable-seng) disable_seng="yes" + ;; + --enable-seng) disable_seng="no" + ;; + --disable-qtvr) disable_qtvr="yes" + ;; + --enable-qtvr) disable_qtvr="no" + ;; + --disable-avi) disable_avi="yes" + ;; + --enable-avi) disable_avi="no" + ;; + --disable-ogg) disable_ogg="yes" + ;; + --enable-ogg) disable_ogg="no" + ;; + --disable-m2ps) disable_m2ps="yes" + ;; + --enable-m2ps) disable_m2ps="no" + ;; + --disable-m2ts) disable_m2ts="yes" + ;; + --enable-m2ts) disable_m2ts="no" + ;; + --disable-m2ts-mux) disable_m2ts_mux="yes" + ;; + --enable-m2ts-mux) disable_m2ts_mux="no" + ;; + --disable-dvb4linux) has_dvb4linux="no" + ;; + --disable-parsers) disable_parsers="yes" + ;; + --enable-parsers) disable_parsers="no" + ;; + --disable-import) disable_import="yes" + ;; + --enable-import) disable_import="no" + ;; + --disable-export) disable_export="yes" + ;; + --enable-export) disable_export="no" + ;; + --disable-swf) disable_swf="yes" + ;; + --enable-swf) disable_swf="no" + ;; + --disable-scene-stats) disable_scene_stats="yes" + ;; + --enable-scene-stats) disable_scene_stats="no" + ;; + --disable-scene-dump) disable_scene_dump="yes" + ;; + --enable-scene-dump) disable_scene_dump="no" + ;; + --disable-scene-encode) disable_scene_encode="yes" + ;; + --enable-scene-encode) disable_scene_encode="no" + ;; + --disable-loader-isoff) disable_loader_isoff="yes" + ;; + --enable-loader-isoff) disable_loader_isoff="no" + ;; + --disable-loader-bt) disable_loader_bt="yes" + ;; + --enable-loader-bt) disable_loader_bt="no" + ;; + --disable-loader-xmt) disable_loader_xmt="yes" + ;; + --enable-loader-xmt) disable_loader_xmt="no" + ;; + --disable-od-dump) disable_od_dump="yes" + ;; + --enable-od-dump) disable_od_dump="no" + ;; + --disable-od-parse) disable_od_parse="yes" + ;; + --enable-od-parse) disable_od_parse="no" + ;; + --disable-isom-dump) disable_isom_dump="yes" + ;; + --enable-isom-dump) disable_isom_dump="no" + ;; + --disable-mcrypt) disable_mcrypt="yes" + ;; + --enable-mcrypt) disable_mcrypt="no" + ;; + --disable-isoff) disable_isoff="yes" + ;; + --enable-isoff) disable_isoff="no" + ;; + --disable-isoff-write) disable_isoff_write="yes" + ;; + --enable-isoff-write) disable_isoff_write="no" + ;; + --disable-isoff-hint) disable_isoff_hint="yes" + ;; + --enable-isoff-hint) disable_isoff_hint="no" + ;; + --disable-isoff-frag) disable_isoff_frag="yes" + ;; + --enable-isoff-frag) disable_isoff_frag="no" + ;; + --disable-isoff-hds) disable_isoff_hds="yes" + ;; + --enable-isoff-hds) disable_isoff_hds="no" + ;; + --disable-streaming) disable_streaming="yes" + ;; + --enable-streaming) disable_streaming="no" + ;; + --disable-player) disable_player="yes" + ;; + --enable-player) disable_player="no" + ;; + --disable-scenegraph) disable_scenegraph="yes" + ;; + --enable-scenegraph) disable_scenegraph="no" + ;; + --disable-dvbx) disable_dvbx="yes" + ;; + --enable-dvbx) disable_dvbx="no" + ;; + --disable-vobsub) disable_vobsub="yes" + ;; + --enable-vobsub) disable_vobsub="no" + ;; + --disable-ttxt) disable_ttxt="yes" + ;; + --enable-ttxt) disable_ttxt="no" + ;; + --disable-ttml) disable_ttml="yes" + ;; + --enable-ttml) disable_ttml="no" + ;; + --disable-saf) disable_saf="yes" + ;; + --enable-saf) disable_saf="no" + ;; + --disable-smgr) disable_smgr="yes" + ;; + --enable-smgr) disable_smgr="no" + ;; + --disable-mpd) disable_mpd="yes" + ;; + --enable-mpd) disable_mpd="no" + ;; + --disable-dash) disable_dash="yes" + ;; + --enable-dash) disable_dash="no" + ;; + --disable-core) disable_core_tools="yes" + ;; + --enable-core) disable_core_tools="no" + ;; + --disable-hevc) disable_hevc="yes" + ;; + --enable-hevc) disable_hevc="no" + ;; + esac +done + + + +if test "$disable_core_tools" = "no"; then + if test "$has_zlib" = "no" ; then + echo "error: zlib not found on system or in local libs" + exit 1 + fi + if test "$dlopen" = "no"; then + if test "$win32" = "no"; then + echo "error: dlopen not found on system" + exit 1 + fi + fi +else +GPAC_SH_FLAGS="" +has_ssl="no" +fi + +#look for OpenGL support or for TinyGL support +LINK3D="" +INCL3D="" +DarwinGL="no" + +if test "$darwin" = "yes" ; then + cat > $TMPC << EOF +#include +#include +int main( void ) { glEnable(GL_NORMALIZE); return 0; } +EOF + +else + cat > $TMPC << EOF +#include +#include +int main( void ) { glEnable(GL_NORMALIZE); return 0; } +EOF + +fi + +if test "$disable_3d" = "no" ; then + if test "$win32" = "yes" ; then + if test "$cygwin" = "yes" ; then + LINK3D="-lw32api/opengl32 -lw32api/glu32" + else + LINK3D="-lopengl32 -lglu32" + fi + elif test "$darwin" = "yes" ; then + LINK3D="-framework OpenGL -framework GLUT" + DarwinGL="yes" + else + LINK3D="-lGL -lGLU -lX11" + fi + if docc $LINK3D $LDFLAGS ; then + has_opengl="yes" + elif docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then + has_opengl="yes" + INCL3D="-I$X11_PATH/include" + LINK3D="-L$X11_PATH/lib $LINK3D" + fi + if test "$has_opengl" = "no" ; then + LINK3D="" + fi +fi + +cat > $TMPC << EOF +#include +int main( void ) { int a ; a = TINYGL ; return 0;} +EOF + +if test "$enable_tinygl" = "yes" ;then + if docc $LDFLAGS -lTinyGL ; then + has_tinygl="yes" + has_opengl="yes" + LINK3D="-lTinyGL" + fi +fi + + + +#look for GECKO support +cat > $TMPCXX << EOF +#include +int main( void ) { return 0; } +EOF + +if docxx -I$xulsdk_path $LDFLAGS ; then + has_xul="system" + xul_flags="-I$xulsdk_path $xul_flags" +fi + +if test "$pkg_config" != "no"; then + if test "$has_xul" = "no" ; then + if $pkg_config --exists libxul 2>>$logs ; then + if docxx -o $TMPO $TMPCXX `$pkg_config --cflags libxul` `$pkg_config --libs libxul` ; then + has_xul="system" + xul_flags="`$pkg_config --cflags libxul` `$pkg_config --libs libxul`" + fi + fi + fi +fi + +if test "$has_xul" = "no" ; then + if docxx $xul_flags -I$local_inc/gecko-sdk/include $LDFLAGS ; then + has_xul="local" + xul_flags="-I$local_inc/gecko-sdk/include $xul_flags" + else + #xulrunner directories are sometimes included through js/xul/ff packages + if test ! "$has_js" = "no" -a ! "$has_js" = "local" ; then + if docxx $js_flags $js_lib_pkg $LDFLAGS ; then + if test "$mozjs_pkgcfg" != "no" ; then + xul_flags=`$pkg_config --cflags $mozjs_pkgcfg` + has_xul="$has_js" + fi + fi + fi + fi +fi + + + +#look for joystick support +cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF +if test "$enable_joystick" = "yes" ;then + if docc $LDFLAGS ; then + has_joystick="yes" + fi +fi + + + +#look for DX support +dx_path="system" +has_mingw_directx="no" +if test "$win32" = "yes" ; then + + cat > $TMPC << EOF +#include +int main( void ) { return 0; } +EOF + + if docc $LDFLAGS ; then + has_mingw_directx="yes" + else + dx_path="$dxsdk_path" + if docc -I$dxsdk_path/include -L$dxsdk_path/lib -lddraw ; then + has_mingw_directx="yes" + fi + fi + +fi + + + +#look for SDL support +sdl_too_old=no +has_sdl=no + +sdl_config="sdl2-config" +if test "$sdl_local" = "yes"; then + sdl_config="$sdl_path/sdl2-config" + sdl_static="yes" +fi + + +#if test "$cross_prefix" = "" ; then + if type $sdl_config >/dev/null 2>>$logs; then + + cat > $TMPC << EOF +#include +#undef main +int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } +EOF + + if test "$sdl_static" = "yes"; then + sdl_lib_flags=`$sdl_config --static-libs` + else + sdl_lib_flags=`$sdl_config --libs` + fi + sdl_cflags=`$sdl_config --cflags` + + if docc $sdl_cflags $LDFLAGS $sdl_lib_flags ; then + _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` + if test "$_sdlversion" -lt 121 ; then + sdl_too_old=yes + else + has_sdl=yes + fi + fi + fi +#fi + +if test "$has_sdl" = "no" ; then + + sdl_config="sdl-config" + if test "$sdl_local" = "yes"; then + sdl_config="$sdl_path/sdl-config" + sdl_static="yes" + fi + + if test "$cross_prefix" = "" ; then + if type $sdl_config >/dev/null 2>>$logs; then + + cat > $TMPC << EOF +#include +#undef main +int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } +EOF + + if test "$sdl_static" = "yes"; then + sdl_lib_flags=`$sdl_config --static-libs` + else + sdl_lib_flags=`$sdl_config --libs` + fi + sdl_cflags=`$sdl_config --cflags` + + if docc $sdl_cflags $LDFLAGS $sdl_lib_flags ; then + _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` + if test "$_sdlversion" -lt 121 ; then + sdl_too_old=yes + else + has_sdl=yes + fi + fi + fi + fi +fi +#end SDL check + + + +#look at endianess +if test -z "$cross_prefix" ; then + + # big/little endian test + cat > $TMPC << EOF +#include +int main(int argc, char ** argv){ +volatile uint32_t i=0x01234567; +return (*((uint8_t*)(&i))) == 0x67; +} +EOF + + if docc $LDFLAGS 2>>$logs ; then + $TMPO && bigendian="yes" + else + echo big/little endian test failed + fi + +else + + # if cross compiling, cannot launch a program, so make a static guess + if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then + bigendian="yes" + fi + +fi + + + +#man dir +if test x"$mandir" = x""; then + mandir="${prefix}/man" +fi + +if test "$static_mp4box" = "yes"; then + has_opengl="no" + has_ssl="no" + has_js="no" + has_jpeg="no" + has_png="no" + has_mad="no" + has_ft="no" + has_openjpeg="no" + has_mad="no" + has_faad="no" + has_xvid="no" + has_ffmpeg="no" + has_ogg="no" + has_theora="no" + has_vorbis="no" + has_a52="no" + has_opensvc="no" + has_openhevc="no" + has_freenect="no" + has_platinum="no" + static_build="yes" +fi + +if test "$cpu" = "sh4"; then + viren_dir="`ls \"$source_path/modules\" | grep viren_out`" + if test "$viren_dir" = "viren_out"; then + enable_depth_compositor="yes" + enable_renoir="yes" + fi +fi + +if test "$disable_player" = "yes" ; then + disable_scenegraph="yes" +fi + +if test "$disable_scenegraph" = "yes" ; then + disable_3d="yes" + disable_svg="yes" + disable_vrml="yes" + disable_x3d="yes" + disable_bifs="yes" + disable_bifs_enc="yes" + disable_laser="yes" + disable_seng="yes" + disable_qtvr="yes" + disable_swf="yes" + disable_scene_stats="yes" + disable_scene_dump="yes" + disable_scene_encode="yes" + disable_loader_isoff="yes" + disable_loader_bt="yes" + disable_loader_xmt="yes" + disable_streaming="yes" + disable_player="yes" + disable_smgr="yes" + has_js="no" +fi + +if test "$disable_mpd" = "yes"; then + disable_dash="yes" +fi + +if test "$disable_od_parse" = "yes" ; then + disable_loader_isoff="yes" + disable_loader_bt="yes" + disable_loader_xmt="yes" +fi + +if test "$disable_parsers" = "yes" ; then + has_jpeg="no" + has_png="no" +fi + +#prepare for config.h writing +TMPH="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.h" +echo "/* Automatically generated by configure */" > $TMPH +echo "#ifndef GF_CONFIG_H" >> $TMPH +echo "#define GF_CONFIG_H" >> $TMPH +echo "#define GPAC_CONFIGURATION \"$GPAC_CONFIGURATION\"" >> $TMPH + +version="`grep '#define GPAC_VERSION ' \"$source_path/include/gpac/version.h\" | cut -d '"' -f 2`" +version_major=`grep '#define GPAC_VERSION_MAJOR ' $source_path/include/gpac/version.h | sed 's/[^0-9]*//g'` +version_minor=`grep '#define GPAC_VERSION_MINOR ' $source_path/include/gpac/version.h | sed 's/[^0-9]*//g'` +version_micro=`grep '#define GPAC_VERSION_MICRO ' $source_path/include/gpac/version.h | sed 's/[^0-9]*//g'` +soname_version="${version_major}.${version_minor}.${version_micro}" + + +if [ -d ".git" ]; then + TAG=$(git describe --tags --abbrev=0 2>>$logs) + VERSION=$(echo `git describe --tags --long 2>>$logs || echo "UNKNOWN"` | sed "s/^$TAG-//") + BRANCH=$(git rev-parse --abbrev-ref HEAD 2>>$logs || echo "UNKNOWN") + revision="$VERSION-$BRANCH" + echo "#define GPAC_GIT_REVISION \"$revision\"" > $source_path/include/gpac/revision.h +else + if [ ! -e "$source_path/include/gpac/revision.h" ]; then + echo "#define GPAC_GIT_REVISION \"UNKNOWN-UNKNOWN\"" > $source_path/include/gpac/revision.h + fi +fi + +echo "" +echo "** System Configuration" +echo "Install prefix: $prefix" +echo "Source path: $source_path" +echo "C compiler: $cc_naked" +echo "C++ compiler: $cxx_naked" +echo "make: $make" +echo "CPU: $cpu" +echo "Big Endian: $bigendian" +if test $cpu = "mips"; then + echo "MMI enabled: $mmi" +fi +echo "" +echo "** GPAC $version rev$revision Core Configuration **" +echo "debug version: $debuginfo" +echo "GProf enabled: $gprof_build" +echo "Static build enabled: $static_build" +echo "Memory tracking enabled: $use_memory_tracking" +echo "Fixed-Point Version: $use_fixed_point" +echo "IPV6 Support: $has_ipv6" +echo "Static Modules: $static_modules" + +if test "$disable_player" = "yes" ; then + echo "Player disabled" + echo "#define GPAC_DISABLE_PLAYER" >> $TMPH + disable_laser="yes" +fi +if test "$disable_smgr" = "yes" ; then +disable_seng="yes" +disable_qtvr="yes" +disable_swf="yes" +disable_scene_stats="yes" +disable_scene_dump="yes" +disable_scene_encode="yes" +disable_loader_isoff="yes" +disable_loader_bt="yes" +disable_loader_xmt="yes" +disable_svg="yes" + echo "Scene Manager disabled" + echo "#define GPAC_DISABLE_SMGR" >> $TMPH +fi +if test "$disable_core_tools" = "yes" ; then + echo "Core tools disabled" + echo "#define GPAC_DISABLE_CORE_TOOLS" >> $TMPH +fi +if test "$disable_svg" = "yes" ; then + echo "SVG disabled" + echo "#define GPAC_DISABLE_SVG" >> $TMPH + disable_laser="yes" +fi +if test "$disable_vrml" = "yes" ; then + echo "MPEG-4/VRML/X3D disabled" + echo "#define GPAC_DISABLE_VRML" >> $TMPH +fi +if test "$disable_x3d" = "yes" ; then + echo "X3D disabled" + echo "#define GPAC_DISABLE_X3D" >> $TMPH +fi +if test "$disable_od" = "yes" ; then + echo "OD Full support disabled" + echo "#define GPAC_MINIMAL_ODF" >> $TMPH +fi +if test "$disable_od_parse" = "yes" ; then + echo "OD Parsing disabled" + echo "#define GPAC_DISABLE_OD_PARSE" >> $TMPH +fi +if test "$disable_bifs" = "yes" ; then + echo "BIFS coder disabled" + echo "#define GPAC_DISABLE_BIFS" >> $TMPH +fi +if test "$disable_bifs_enc" = "yes" ; then + echo "BIFS encoder disabled" + echo "#define GPAC_DISABLE_BIFS_ENC" >> $TMPH +fi +if test "$disable_laser" = "yes" ; then + echo "LASeR coder disabled" + echo "#define GPAC_DISABLE_LASER" >> $TMPH +fi +if test "$disable_saf" = "yes" ; then + echo "SAF container disabled" + echo "#define GPAC_DISABLE_SAF" >> $TMPH +fi +if test "$disable_seng" = "yes" ; then + echo "Scene encoder engine disabled" + echo "#define GPAC_DISABLE_SENG" >> $TMPH +fi +if test "$disable_qtvr" = "yes" ; then + echo "Cubic QTVR import disabled" + echo "#define GPAC_DISABLE_QTVR" >> $TMPH +fi +if test "$disable_avi" = "yes" ; then + echo "AVI disabled" + echo "#define GPAC_DISABLE_AVILIB" >> $TMPH +fi +if test "$disable_ogg" = "yes" ; then + echo "OGG disabled" + echo "#define GPAC_DISABLE_OGG" >> $TMPH +fi +if test "$disable_m2ps" = "yes" ; then + echo "MPEG-2 PS disabled" + echo "#define GPAC_DISABLE_MPEG2PS" >> $TMPH +fi +if test "$disable_m2ts" = "yes" ; then + echo "MPEG-2 TS disabled" + echo "#define GPAC_DISABLE_MPEG2TS" >> $TMPH +fi +if test "$disable_m2ts_mux" = "yes" ; then + echo "MPEG-2 TS Multiplexer disabled" + echo "#define GPAC_DISABLE_MPEG2TS_MUX" >> $TMPH +fi +if test "$disable_parsers" = "yes" ; then + echo "AV Parsers disabled" + echo "#define GPAC_DISABLE_AV_PARSERS" >> $TMPH +fi +if test "$disable_import" = "yes" ; then + echo "Media importers disabled" + echo "#define GPAC_DISABLE_MEDIA_IMPORT" >> $TMPH +fi +if test "$disable_export" = "yes" ; then + echo "Media exmporters disabled" + echo "#define GPAC_DISABLE_MEDIA_EXPORT" >> $TMPH +fi +if test "$disable_swf" = "yes" ; then + echo "SWF import disabled" + echo "#define GPAC_DISABLE_SWF_IMPORT" >> $TMPH +fi +if test "$disable_scenegraph" = "yes" ; then + echo "Scene Graph disabled" + echo "#define GPAC_DISABLE_SCENEGRAPH" >> $TMPH +fi +if test "$disable_scene_stats" = "yes" ; then + echo "Scene statistics disabled" + echo "#define GPAC_DISABLE_SCENE_STATS" >> $TMPH +fi +if test "$disable_scene_dump" = "yes" ; then + echo "Scene dump disabled" + echo "#define GPAC_DISABLE_SCENE_DUMP" >> $TMPH +fi +if test "$disable_scene_encode" = "yes" ; then + echo "Scene encoder to ISO FF disabled" + echo "#define GPAC_DISABLE_SCENE_ENCODER" >> $TMPH +fi +if test "$disable_loader_isoff" = "yes" ; then + echo "Scene loader from ISO FF disabled" + echo "#define GPAC_DISABLE_LOADER_ISOM" >> $TMPH +fi +if test "$disable_loader_bt" = "yes" ; then + echo "BT/WRL Scene loader disabled" + echo "#define GPAC_DISABLE_LOADER_BT" >> $TMPH +fi +if test "$disable_loader_xmt" = "yes" ; then + echo "XMT/X3D Scene loader disabled" + echo "#define GPAC_DISABLE_LOADER_XMT" >> $TMPH +fi +if test "$disable_od_dump" = "yes" ; then + echo "OD dump disabled" + echo "#define GPAC_DISABLE_OD_DUMP" >> $TMPH +fi +if test "$disable_isom_dump" = "yes" ; then + echo "ISOM dump disabled" + echo "#define GPAC_DISABLE_ISOM_DUMP" >> $TMPH +fi +if test "$disable_mcrypt" = "yes" ; then + echo "MCrypt disabled" + echo "#define GPAC_DISABLE_MCRYPT" >> $TMPH +fi +if test "$disable_isoff" = "yes" ; then + echo "ISO File Format disabled" + echo "#define GPAC_DISABLE_ISOM" >> $TMPH +fi +if test "$disable_isoff_write" = "yes" ; then + echo "ISO File Format write disabled" + echo "#define GPAC_DISABLE_ISOM_WRITE" >> $TMPH +fi +if test "$disable_isoff_hint" = "yes" ; then + echo "ISO File Format hinting disabled" + echo "#define GPAC_DISABLE_ISOM_HINTING" >> $TMPH +fi +if test "$disable_isoff_frag" = "yes" ; then + echo "ISO File Format fragments disabled" + echo "#define GPAC_DISABLE_ISOM_FRAGMENTS" >> $TMPH +fi +if test "$disable_isoff_hds" = "yes" ; then + echo "ISO File Format Adobe HDS disabled" + echo "#define GPAC_DISABLE_ISOM_ADOBE" >> $TMPH +fi + +if test "$disable_streaming" = "yes" ; then + echo "RTP/RTSP/SDP streaming disabled" + echo "#define GPAC_DISABLE_STREAMING" >> $TMPH +fi +if test "$disable_dvbx" = "no" ; then + echo "DVB MPE and DSM-CC disabled" + echo "#define GPAC_ENABLE_MPE" >> $TMPH + echo "#define GPAC_ENABLE_DSMCC" >> $TMPH +fi +if test "$disable_vobsub" = "yes" ; then + echo "VobSub disabled" + echo "#define GPAC_DISABLE_VOBSUB" >> $TMPH +fi +if test "$disable_ttxt" = "yes" ; then + echo "3GPP/Apple TimedText disabled" + echo "#define GPAC_DISABLE_TTXT" >> $TMPH +fi + +if test "$disable_ttml" = "yes" ; then + echo "TTML TimedText disabled" + echo "#define GPAC_DISABLE_TTML" >> $TMPH +fi + +if test "$enable_depth_compositor" = "yes" ; then + echo "Depth Compositor enabled" + echo "#define GF_SR_USE_DEPTH" >> $TMPH +fi + +if test "$disable_mpd" = "yes" ; then + echo "HLS and DASH Manifest Disabled" + echo "#define GPAC_DISABLE_MPD" >> $TMPH +fi + +if test "$disable_dash" = "yes" ; then + echo "Adaptive HTTP Streaming Client disabled" + echo "#define GPAC_DISABLE_DASH_CLIENT" >> $TMPH +fi + +if test "$disable_hevc" = "yes" ; then + echo "HEVC Support disabled" + echo "#define GPAC_DISABLE_HEVC" >> $TMPH +fi + +echo "" + +echo "** Detected libraries **" +echo "zlib: $has_zlib" + +if test "$win32" != "yes" ; then + echo "OSS Audio: $has_oss_audio" + echo "ALSA Audio: $has_alsa" + echo "Jack Audio: $has_jack" + echo "PulseAudio Audio: $has_pulseaudio" + echo "DirectFB support: $has_directfb" + echo "X11 Shared Memory support: $has_x11_shm (path: $X11_PATH)" + echo "X11 XVideo support: $has_x11_xv" +fi + +echo "SDL Support: $has_sdl" +if test "$sdl_too_old" = "yes" ; then + echo "SDL Version too old - please upgrade for SDL support" +fi +echo "OpenGL support: $has_opengl" +echo "TinyGL support: $has_tinygl" +echo "OpenSSL support: $has_ssl" + +echo "Mozilla XUL/GECKO support: $has_xul" + +if test "$win32" = "yes" ; then + echo "DirectX Support: $has_mingw_directx" +fi +if test "$linux" = "yes" ; then + echo "DVB Support: $has_dvb4linux" +fi + +echo "XMLRPC Support: $has_xmlrpc" + +if test "$wx_too_old" = "yes" ; then + has_wx="no" + echo "wxWidgets Version too old - please upgrade to 2.6.0 for wxWidgets support" +fi +if test "$has_wx" = "yes" ; then + echo "wxWidgets support: Version $wx_version" +else + echo "wxWidgets support: no" +fi + + +echo "" +echo "** Extra Libraries used **" +echo "SpiderMonkey: $has_js" +echo "FreeType: $has_ft" +echo "JPEG: $has_jpeg" +echo "OpenJPEG: $has_openjpeg" +echo "PNG: $has_png" +echo "MAD: $has_mad" +echo "FAAD: $has_faad" +echo "XVID: $has_xvid" +echo "FFMPEG: $has_ffmpeg" +echo "Xiph OGG: $has_ogg" +echo "Platinum UPnP: $has_platinum" +echo "AVCap: $has_avcap" +if test "$has_ogg" = "no"; then + has_ogg="no" +else + echo "Xiph Vorbis: $has_vorbis" + echo "Xiph Theora: $has_theora" +fi +echo "A52 (AC3): $has_a52" +echo "OpenSVCDecoder: $has_opensvc" +echo "OpenHEVCDecoder: $has_openhevc" +echo "Freenect: $has_freenect" + +if test "$enable_renoir" = "yes" ; then + echo "Renoir enabled - make sure the driver libraries are present in modules/viren_out directory" +fi + +if test "$has_amr_nb_fixed" = "yes" ; then + echo "" + echo "*** AMR NB FIXED-POINT NOTICE ***" + echo "Make sure you have downloaded TS26.073 from:" + echo "http://www.3gpp.org/ftp/Specs/archive/26_series/26.073/26073-*.zip" + echo "or through gpac_extra_libs and extracted src to modules/amr_dec/amr_nb" + echo "without overwriting typedefs.h file" + echo "" +fi + +if test "$has_amr_nb" = "yes" ; then + echo "" + echo "*** AMR NB NOTICE ***" + echo "Make sure you have downloaded TS26.104 from:" + echo "http://www.3gpp.org/ftp/Specs/archive/26_series/26.104/26104-*.zip" + echo "or through gpac_extra_libs and extracted src to modules/amr_float_dec/amr_nb_ft" + echo "without overwriting typedefs.h file" + echo "" +fi + + +if test "$has_amr_wb" = "yes" ; then + echo "" + echo "*** AMR WB NOTICE ***" + echo "Make sure you have downloaded TS26.204 from:" + echo "http://www.3gpp.org/ftp/Specs/archive/26_series/26.204/26204-*.zip" + echo "or through gpac_extra_libs and extracted src to modules/amr_float_dec/amr_wb_ft" + echo "without overwriting typedefs.h file" + echo "" +fi + +echo "" + +#needs gmon for win32 gprof +if test "$gprof_build" = "yes"; then + if test "$win32" = "yes"; then + extralibs="$extralibs -lgmon" + fi +fi + +if test "$darwin" = "yes" ; then + CFLAGS="$CFLAGS_DIR $CFLAGS" +fi + +ldir=`pwd` +CFLAGS="$CFLAGS -DGPAC_HAVE_CONFIG_H -I\"$ldir\"" +if test "$win32" = "no" ; then + CFLAGS="$CFLAGS -fvisibility=\"hidden\"" +fi +CXXFLAGS="$CXXFLAGS" + + +echo "Creating config.mak" +echo "# Automatically generated by configure - do not modify" > config.mak + +echo "GPAC_CONFIGURATION=$GPAC_CONFIGURATION" >> config.mak + +echo "prefix=$prefix" >> config.mak +echo "DESTDIR=$DESTDIR" >> config.mak +echo "moddir=$prefix/$libdir/gpac" >> config.mak +echo "moddir_path=$prefix/$libdir/gpac" >> config.mak +echo "mandir=$mandir" >> config.mak +echo "tinygl_target_bin_dir=$target_bin_dir" >> config.mak +echo "MAKE=$make" >> config.mak + +if test "$verbose" = "yes" ; then +echo "CC=$cc_naked" >> config.mak +echo "AR=$ar" >> config.mak +echo "RANLIB=$ranlib" >> config.mak +echo "STRIP=$strip" >> config.mak +echo "WINDRES=$windres" >> config.mak +else +echo "CC=@$cc_naked" >> config.mak +echo "AR=@$ar" >> config.mak +echo "RANLIB=@$ranlib" >> config.mak +echo "STRIP=@$strip" >> config.mak +echo "WINDRES=$windres" >> config.mak +fi +echo "INSTALL=$install" >> config.mak +echo "LIBTOOL=libtool" >> config.mak + +echo "INSTFLAGS=$instflags" >> config.mak +echo "OPTFLAGS=$CFLAGS" >> config.mak +echo "CXXFLAGS=$CXXFLAGS" >> config.mak +echo "LDFLAGS=$LDFLAGS" >> config.mak +echo "SHFLAGS=$SHFLAGS" >> config.mak +echo "libdir=$libdir" >> config.mak + +echo "STATIC_MODULES=$static_modules" >> config.mak + +#for cross-compilation +if test "$cross_prefix" != "" ; then + echo "CROSS_COMPILING=yes" >> config.mak +fi + +if test "$cpu" = "x86" ; then + echo "TARGET_ARCH_X86=yes" >> config.mak +elif test "$cpu" = "armv4l" ; then + echo "TARGET_ARCH_ARMV4L=yes" >> config.mak +elif test "$cpu" = "alpha" ; then + echo "TARGET_ARCH_ALPHA=yes" >> config.mak +elif test "$cpu" = "sparc64" ; then + echo "TARGET_ARCH_SPARC64=yes" >> config.mak +elif test "$cpu" = "powerpc" ; then + echo "TARGET_ARCH_POWERPC=yes" >> config.mak +elif test "$cpu" = "mips" ; then + echo "TARGET_ARCH_MIPS=yes" >> config.mak +fi + + +if test "$bigendian" = "yes" ; then + echo "IS_BIGENDIAN=yes" >> config.mak + echo "#define GPAC_BIG_ENDIAN" >> $TMPH +fi +echo "EXTRALIBS=$extralibs" >> config.mak +echo "VERSION=$version" >>config.mak +echo "VERSION_MAJOR=$version_major" >>config.mak +echo "VERSION_SONAME=$soname_version" >>config.mak + +if test "$use_fixed_point" = "yes"; then + echo "#define GPAC_FIXED_POINT" >> $TMPH +fi + +if test "$use_memory_tracking" = "yes"; then + echo "#define GPAC_MEMORY_TRACKING" >> $TMPH +fi + + +if test "$win32" = "yes" ; then + echo "CONFIG_WIN32=yes" >> config.mak + echo "CONFIG_OS=CONFIG_WIN32" >> config.mak + echo "#define GPAC_CONFIG_WIN32" >> $TMPH + if test "$cygwin" = "yes" ; then + echo "#define ftello64 ftell" >> $TMPH + echo "#define fseeko64 fseek" >> $TMPH + fi +elif test "$linux" = "yes" ; then + echo "CONFIG_LINUX=yes" >> config.mak + echo "CONFIG_OS=CONFIG_LINUX" >> config.mak + echo "#define GPAC_CONFIG_LINUX" >> $TMPH +elif test "$freebsd" = "yes" ; then + echo "CONFIG_FREEBSD=yes" >> config.mak + echo "CONFIG_OS=CONFIG_FREEBSD" >> config.mak + echo "#define GPAC_CONFIG_FREEBSD" >> $TMPH +elif test "$darwin" = "yes" ; then + echo "CONFIG_DARWIN=yes" >> config.mak + echo "CONFIG_OS=CONFIG_DARWIN" >> config.mak + echo "#define GPAC_CONFIG_DARWIN" >> $TMPH + if test "$DarwinGL" = "yes" ; then + echo "#define CONFIG_DARWIN_GL" >> $TMPH + fi + echo "mac_apps=$Mac_Applications" >> config.mak +elif test "$sunos" = "yes" ; then + echo "CONFIG_SUNOS=yes" >> config.mak + echo "CONFIG_OS=CONFIG_SUNOS" >> config.mak + echo "#define GPAC_CONFIG_SUNOS" >> $TMPH +else + echo "CONFIG_OS=CONFIG_GEN" >> config.mak + echo "#define GPAC_CONFIG_GENERIC" >> $TMPH +fi + +if test "$win32" = "no" ; then + echo "GPAC_SH_FLAGS=$GPAC_SH_FLAGS" >> config.mak + echo "EXE_SUFFIX=" >> config.mak + echo "DYN_LIB_SUFFIX=$DYN_LIB_SUFFIX" >> config.mak +else + echo "EXE_SUFFIX=.exe" >> config.mak + echo "DYN_LIB_SUFFIX=.dll" >> config.mak +fi + + +echo "INSTFLAGS=$INSTFLAGS" >> config.mak + +echo "CONFIG_JS=$has_js" >> config.mak +if test "$has_js" = "no" ; then + has_js="no" +else + if test "$has_js" = "local" ; then + js_flags="-DXP_UNIX -I$local_inc/js" + js_lib="-ljs" + fi + echo "JS_FLAGS=$js_flags" >> config.mak + echo "JS_LIBS=$js_lib" >> config.mak + echo "#define GPAC_HAS_SPIDERMONKEY" >> $TMPH +fi +if test "$has_zlib" = "no" -o "$has_zlib" = "force-no" ; then + echo "#define GPAC_DISABLE_ZLIB" >> $TMPH + echo "CONFIG_ZLIB=no" >> config.mak +else + echo "CONFIG_ZLIB=$has_zlib" >> config.mak +fi +echo "CONFIG_FT=$has_ft" >> config.mak + +echo "CONFIG_JPEG=$has_jpeg" >> config.mak +if test "$has_jpeg" != "no" ; then + echo "#define GPAC_HAS_JPEG" >> $TMPH +fi + +echo "CONFIG_PNG=$has_png" >> config.mak +if test "$has_png" != "no" ; then + echo "#define GPAC_HAS_PNG" >> $TMPH +fi + +echo "CONFIG_JP2=$has_openjpeg" >> config.mak +echo "CONFIG_FAAD=$has_faad" >> config.mak +echo "CONFIG_MAD=$has_mad" >> config.mak +echo "CONFIG_XVID=$has_xvid" >> config.mak +echo "CONFIG_OGG=$has_ogg" >> config.mak +echo "CONFIG_VORBIS=$has_vorbis" >> config.mak +echo "CONFIG_THEORA=$has_theora" >> config.mak +echo "CONFIG_FFMPEG=$has_ffmpeg" >> config.mak +if test "$has_ffmpeg" = "no"; then +echo "DISABLE_DASHCAST=yes" >> config.mak +else + echo "ffmpeg_cflags=$ffmpeg_cflags" >> config.mak + echo "ffmpeg_lflags=$ffmpeg_lflags" >> config.mak + echo "CONFIG_LIBAV=$is_libav" >> config.mak + echo "CONFIG_LIBAVRESAMPLE=$has_libavresample" >> config.mak +fi +echo "CONFIG_FFMPEG_OLD=$old_ffmpeg_inc" >> config.mak + +echo "CONFIG_OSS_AUDIO=$has_oss_audio" >> config.mak +echo "CONFIG_ALSA=$has_alsa" >> config.mak +echo "CONFIG_JACK=$has_jack" >> config.mak +echo "CONFIG_A52=$has_a52" >> config.mak +echo "CONFIG_PULSEAUDIO=$has_pulseaudio" >> config.mak +echo "CONFIG_FREENECT=$has_freenect" >> config.mak +if test "$has_freenect" != "no" +then + echo "FREENECT_CFLAGS=$freenect_flags" >> config.mak + echo "FREENECT_LDLAGS=$freenect_ld" >> config.mak +fi + +echo "DISABLE_PLAYER=$disable_player" >> config.mak +echo "DISABLE_STREAMING=$disable_streaming" >> config.mak +echo "DISABLE_SVG=$disable_svg" >> config.mak +echo "DISABLE_LASER=$disable_laser" >> config.mak +echo "DISABLE_SAF=$disable_saf" >> config.mak +echo "DISABLE_BIFS=$disable_bifs" >> config.mak +echo "DISABLE_SENG=$disable_seng" >> config.mak +echo "DISABLE_LOADER_ISOFF=$disable_loader_isoff" >> config.mak +echo "DISABLE_LOADER_BT=$disable_loader_bt" >> config.mak +echo "DISABLE_LOADER_XMT=$disable_loader_xmt" >> config.mak +echo "DISABLE_LOADER_QTVR=$disable_qtvr" >> config.mak +echo "DISABLE_LOADER_SWF=$disable_swf" >> config.mak +echo "DISABLE_SCENE_STATS=$disable_scene_stats" >> config.mak +echo "DISABLE_SCENE_DUMP=$disable_scene_dump" >> config.mak +echo "DISABLE_SCENE_ENCODE=$disable_scene_encode" >> config.mak +echo "DISABLE_SCENEGRAPH=$disable_scenegraph" >> config.mak +echo "DISABLE_MCRYPT=$disable_mcrypt" >> config.mak +echo "DISABLE_DVBX=$disable_dvbx" >> config.mak +echo "DISABLE_AVILIB=$disable_avi" >> config.mak +echo "DISABLE_M2PS=$disable_m2ps" >> config.mak +echo "DISABLE_OGG=$disable_ogg" >> config.mak +echo "DISABLE_ISOFF=$disable_isoff" >> config.mak +echo "DISABLE_ISOFF_HINT=$disable_isoff_hint" >> config.mak +echo "DISABLE_VOBSUB=$disable_vobsub" >> config.mak +echo "DISABLE_TTXT=$disable_ttxt" >> config.mak +echo "DISABLE_TTML=$disable_ttml" >> config.mak +echo "DISABLE_SMGR=$disable_smgr" >> config.mak +echo "DISABLE_AV_PARSERS=$disable_parsers" >> config.mak +echo "DISABLE_MEDIA_IMPORT=$disable_import" >> config.mak +echo "DISABLE_MEDIA_EXPORT=$disable_export" >> config.mak +echo "DISABLE_MPD=$disable_mpd" >> config.mak +echo "DISABLE_DASH_CLIENT=$disable_dash" >> config.mak +echo "DISABLE_CORE_TOOLS=$disable_core_tools" >> config.mak +echo "DISABLE_OD_DUMP=$disable_od_dump" >> config.mak +echo "DISABLE_OD_PARSE=$disable_od_parse" >> config.mak +echo "MINIMAL_OD=$disable_od" >> config.mak +echo "DISABLE_ISOM_ADOBE=$disable_isoff_hds" >> config.mak + +if test "$disable_parsers" = "yes" ; then + disable_m2ts_mux="yes" +fi +echo "DISABLE_M2TS_MUX=$disable_m2ts_mux" >> config.mak +echo "DISABLE_M2TS=$disable_m2ts" >> config.mak + + +echo "GPAC_USE_TINYGL=$has_tinygl" >> config.mak +echo "OGL_INCLS=$INCL3D" >> config.mak + +echo "HAS_OPENGL=$has_opengl" >> config.mak + +if test "$has_opengl" = "yes" ; then + echo "OGL_LIBS=$LINK3D" >> config.mak +else + echo "#define GPAC_DISABLE_3D" >> $TMPH +fi + +if test "$has_tinygl" = "yes" ; then + echo "#define GPAC_USE_TINYGL" >> $TMPH +fi + +echo "ENABLE_JOYSTICK=$has_joystick" >> config.mak + +echo "HAS_OPENSSL=$has_ssl" >> config.mak +if test "$has_ssl" = "yes" ; then + echo "SSL_LIBS=$LINK_SSL" >> config.mak + echo "#define GPAC_HAS_SSL" >> $TMPH +fi + +echo "CONFIG_SDL=$has_sdl" >> config.mak +if test "$has_sdl" = "yes" ; then + echo "SDL_CFLAGS=$sdl_cflags" >> config.mak + echo "SDL_LIBS=$sdl_lib_flags" >> config.mak +fi +if test "$has_ft" = "no" ; then + has_ft="no" +else + echo "FT_CFLAGS=$ft_cflags" >> config.mak + echo "FT_LIBS=$ft_lflags" >> config.mak +fi +echo "CONFIG_AMR_NB=$has_amr_nb_fixed" >> config.mak +echo "CONFIG_AMR_NB_FT=$has_amr_nb" >> config.mak +echo "CONFIG_AMR_WB_FT=$has_amr_wb" >> config.mak +echo "DEBUGBUILD=$debuginfo" >> config.mak +echo "GPROFBUILD=$gprof_build" >> config.mak +echo "MP4BOX_STATIC=$static_mp4box" >> config.mak +echo "STATICBUILD=$static_build" >> config.mak + +echo "CONFIG_IPV6=$has_ipv6" >> config.mak +if test "$has_ipv6" = "yes" ; then + echo "#define GPAC_HAS_IPV6" >> $TMPH +fi + +if test "$is_64" = "yes" ; then + echo "#define GPAC_64_BITS" >> $TMPH +fi + +if test "$win32" = "yes" ; then + echo "CONFIG_DIRECTX=$has_mingw_directx" >> config.mak + if test "$has_mingw_directx" = "yes" ; then + echo "DX_PATH=$dx_path" >> config.mak + fi +fi + +echo "USE_WXWIDGETS=$has_wx" >> config.mak +if test "$has_wx" = "yes"; then + echo "WX_CFLAGS=$wx_cflags" >> config.mak + echo "WX_LFLAGS=$wx_lflags" >> config.mak +fi + +echo "CONFIG_PLATINUM=$has_platinum" >> config.mak + +echo "CONFIG_AVCAP=$has_avcap" >> config.mak +if test "$has_avcap" = "yes" ; then + echo "AVCAP_CFLAGS=$avcap_cflags" >> config.mak + echo "AVCAP_LDFLAGS=$avcap_ldflags" >> config.mak +fi + +echo "CONFIG_OPENSVC=$has_opensvc" >> config.mak +if test "$has_opensvc" = "yes" ; then + echo "OSVC_CFLAGS=$osvc_cflags" >> config.mak + echo "OSVC_LDFLAGS=$osvc_ldflags" >> config.mak +fi + +echo "CONFIG_OPENHEVC=$has_openhevc" >> config.mak +if test "$has_openhevc" = "yes" ; then + echo "OHEVC_CFLAGS=$ohevc_cflags" >> config.mak + echo "OHEVC_LDFLAGS=$ohevc_ldflags" >> config.mak +fi + +echo "MOZILLA_DIR=$moz_path" >> config.mak + +echo "CONFIG_XUL=$has_xul" >> config.mak +if test "$has_xul" != "no"; then + echo "XUL_CFLAGS=$xul_flags" >> config.mak +fi + +echo "LINUX_DVB=$has_dvb4linux" >> config.mak +if test "$has_dvb4linux" = "yes"; then + echo "#define GPAC_HAS_LINUX_DVB" >> $TMPH +fi + +echo "XMLRPC_INC=$has_xmlrpc" >> config.mak + +if test "$has_oss_audio" != "no"; then + echo "OSS_INC_TYPE=$has_oss_audio" >> config.mak + echo "OSS_CFLAGS=$OSS_CFLAGS" >> config.mak + echo "OSS_LDFLAGS=$OSS_LDFLAGS" >> config.mak +fi + +echo "CONFIG_DIRECTFB=$has_directfb" >> config.mak +echo "DIRECTFB_INC_PATH=$directfb_inc" >> config.mak +echo "DIRECTFB_LIB=$directfb_lib" >> config.mak + +echo "CONFIG_X11=$has_x11" >> config.mak + +if test "$has_x11_shm" = "yes"; then + echo "USE_X11_SHM=$has_x11_shm" >> config.mak +fi +if test "$has_x11_xv" = "yes"; then + echo "USE_X11_XV=$has_x11_xv" >> config.mak +fi + +if test "$is_64" = "yes"; then +#not on OSX ... +if test "$darwin" = "yes"; then + echo "X11_LIB_PATH=$X11_PATH/lib" >> config.mak +else + echo "X11_LIB_PATH=$X11_PATH/lib64" >> config.mak +fi +else + echo "X11_LIB_PATH=$X11_PATH/lib" >> config.mak +fi +echo "X11_INC_PATH=$X11_PATH/include" >> config.mak + +echo "RENOIR_ENABLE=$enable_renoir" >> config.mak + +GPAC_ENST_INC=no +GPAC_ENST=no +enst_dir="`ls \"$source_path/src/\" | grep enst`" +if test "$enst_dir" = "enst"; then + echo "GPAC Proprietary Extensions enabled" + GPAC_ENST_INC=yes + #we need libiconv for eit & co + cat > $TMPC << EOF +#include +int main( void ) { +return 0; +} +EOF + + if docc -L$local_lib -liconv ; then + GPAC_ENST=yes + echo "LIBGPAC_ENST=`cd src; ls enst/*.c | sed -e 's/\.c/.o/' | tr -s '\r\n' ' ' ; cd ..`" >> config.mak + else + echo "Couldn't find libiconv - disabling GPAC ENST extensions" + GPAC_ENST="no" + fi +fi +echo "GPAC_ENST=$GPAC_ENST" >> config.mak +echo "GPAC_ENST_INC=$GPAC_ENST" >> config.mak + + + +#build tree in object directory if source path is different from current one +if test "$source_path_used" = "yes" ; then + + echo "Creating compilation tree image" + SRC_DIRS="src src/utils src/isomedia src/ietf src/odf src/bifs src/scenegraph src/terminal src/mcrypt src/media_tools src/scene_manager src/compositor src/laser" + + APP_DIRS="applications/mp4box applications/mp4client applications/osmozilla applications/osmo4_wx applications/mp42ts applications/dashcast" + + for dir in $SRC_DIRS ; do + mkdir -p "$dir" + done + ln -sf "$source_path/Makefile" Makefile + ln -sf "$source_path/src/Makefile" src/Makefile + + mkdir -p applications + ln -sf "$source_path/applications/Makefile" applications/Makefile + mkdir -p applications/testapps + + for dir in $APP_DIRS ; do + mkdir -p "$dir" + ln -sf "$source_path/$dir/Makefile" "$dir/Makefile" + done + + + cur_dir="`pwd`" + cd "$source_path/" + MOD_DIRS="`ls -d modules/*/`" + cd "$cur_dir" + + mkdir -p modules + ln -sf "$source_path/modules/Makefile" modules/Makefile + + for dir in $MOD_DIRS ; do + if [ -f "$source_path/$dir/Makefile" ]; then + mkdir -p "$dir" + ln -sf "$source_path/$dir/Makefile" "$dir/Makefile" + fi + done + if test "$has_mingw_directx" = "yes"; then + ln -sf "$source_path/modules/dx_hw/hand.cur" modules/dx_hw/hand.cur + ln -sf "$source_path/modules/dx_hw/collide.cur" modules/dx_hw/collide.cur + fi + + cd "$cur_dir" + + echo "SRC_LOCAL_PATH=no" >> config.mak +else + echo "SRC_LOCAL_PATH=yes" >> config.mak +fi + +echo "SRC_PATH=$source_path" >> config.mak +echo "BUILD_PATH=$build_path" >> config.mak +echo "LOCAL_INC_PATH=$local_inc" >> config.mak + + +echo "#endif" >> $TMPH + + +#do not overwrite config.h if unchanged to avoid superfluous rebuilds. +if ! cmp -s $TMPH config.h ; then + rm -f config.h + mv -f $TMPH config.h +else + echo "config.h is unchanged" +fi + +echo "Check config.log for detection failures" + +rm -f $TMPO $TMPC $TMPE $TMPS $TMPCXX $TMPH + + +if [ ! -d "./bin" ] ; then + mkdir ./bin +fi +if [ ! -d "./bin/gcc" ] ; then + mkdir ./bin/gcc +fi +if [ ! -d "./bin/gcc/temp" ] ; then + mkdir ./bin/gcc/temp +fi + + +echo '%.opic : %.c' >> config.mak +if test "$verbose" = "no" ; then +echo ' @echo " CC $<"' >> config.mak +fi +echo ' $(CC) $(CFLAGS) $(PIC_CFLAGS) -c $< -o $@' >> config.mak + +echo '%.o : %.c' >> config.mak +if test "$verbose" = "no" ; then +echo ' @echo " CC $<"' >> config.mak +fi +echo ' $(CC) $(CFLAGS) -c -o $@ $<' >> config.mak + +echo '%.o: %.cpp' >> config.mak +if test "$verbose" = "no" ; then +echo ' @echo " CC $<"' >> config.mak +fi +echo ' $(CXX) $(CFLAGS) -c -o $@ $<' >> config.mak + +#pkg-config +echo "prefix=$prefix" > gpac.pc +echo "exec_prefix=\${prefix}" >> gpac.pc +echo "libdir=\${exec_prefix}/$libdir" >> gpac.pc +echo "includedir=\${exec_prefix}/include" >> gpac.pc +echo "" >> gpac.pc +echo "Name: gpac" >> gpac.pc +echo "Description: GPAC Multimedia Framework" >> gpac.pc +echo "URL: http://gpac.sourceforge.net" >> gpac.pc +echo "Version:$version" >> gpac.pc +echo "Cflags: -I\${prefix}/include/gpac" >> gpac.pc +echo "Libs: -L\${libdir} -lgpac" >> gpac.pc + +echo "Done - type 'make help' for make info, 'make' to build" diff --git a/doc/CODING_STYLE b/doc/CODING_STYLE new file mode 100644 index 0000000..9440327 --- /dev/null +++ b/doc/CODING_STYLE @@ -0,0 +1,133 @@ +GPAC coding style + +Introduction + coding styles only concern the GPAC library (M4Systems in GPAC<=0.3.0, libgpac now), and, although recommended, are not mandatory for plugins + or applications development. + + AStyle is a code beautifier tool. Code should be compliant with the following pattern provided by AStyle : + AStyle -r --indent=tab '*.c' '*.h' '*.cpp' '*.hpp' + +1 Exported symbols + + 1.0 Informative note + The GF_ or gf_ stands for "gpac framework" + + 1.1 typedef of structures - typedef of base types - typedef of functions + +All symbols defined within libgpac library and exported for application development purposes shall begin be named GF_* +with the first character of "*" being in capital, regardless of their functionality. +For example, GF_Thread (structure), GF_Err (redefined type), GF_LineCap (enum typedef) + +All structure typedefs, whether defined (declaration exported through ehaders) or not (declaration intern to the GPAC core lib), must follow +this principle. +Furthermore, typedef of non exported structure shall only apply to the structure itself, not a pointer to it. + typedef struct _my_gpac_thingy *GF_LPMYGPACSTUFF; /*this is FORBIDDEN*/ + typedef struct _my_gpac_thingy GF_MyGPACStuff; /*this is OK*/ +This will allow easy exporting of structure declaration if needed at some point in the development. + + + 1.2 constants + +All constants (whether #defines or enums) shall be in capital letters and begin with "GF_" and use "_" for word separation +For example, error code GF_BAD_PARAM. + +Enums names shall refer to the main module they are used in through a keyword right after the GF_ . +For example, + * enums refering to file format (isomedia) will be prefixed by GF_ISOM_ + * enums refering to MPEG-4 OD tools (odf) will be prefixed by GF_ODF_ + + 1.3 functions + +All exported functions and pointer to functions shall begin with "gf_". The name shall refer to the main module they are sued in +through a keyword right after the gf_ when reasonable (gf_isom_, gf_odf_, gf_term_), or to the tool they refer to (gf_bs_, gf_url, ...) + +2 Miscalleanous + +All exported functions' names shall be in lower case exclusively. +All exported functions' parameters should be in lower case exclusively. +Exported structures may use case in any fashion as long as they respect the rules expressed in section 1 above. +Exported structures member should preferably all be lower case - this may not be feasible for scene graph nodes & like... + +All exported header files shall be in lower case +All source files within the gpac core shall be in lower case + +All comments should be C-like ones (/**/) not C++ ones (//) +All exported headers documentation should be written with dowygen syntax +All constructor-like functions should be of style gf_zzz_new +All destructor like functions should be of style gf_zzz_del + +3 Rearchitecture of the GPAC repository + + This recaps the changes between gpac 0.3.0 and gpac 0.4.0 as far as the core architecture is concerned. + + + The former M4Systems library is now simply libGPAC (eg libgpac.lib, libgpac.dll, libgpac.so, libgpac.a) + Currently no decision has been taken regarding splitting of this library in smaller packages, this still needs discussion. + + directory architecture: + /gpac + /gpac/applications/ + former Applications/, misc renames + /gpac/applications/generators: former SceneGenerators + /gpac/applications/testapps: added for apps testing some features of gpac (currently only BIFSEngine tester) + /gpac/bin + rename of directories: + arm_debug -> arm_ppc02_deb + arm_release -> arm_ppc02_rel + Debug -> w32_deb + Release -> w32_rel + /gpac/build: former IDEs directory, with project files for MS eVC*/VC* + /gpac/doc + /gpac/doc/libgpac: future place for doc of all exported functions from libgpac + /gpac/extra_lib + /gpac/extra_lib/include + unchanged + /gpac/extra_lib/lib + rename of directories: + arm_debug -> arm_ppc02_deb + arm_release -> arm_ppc02_rel + w32_debug -> w32_deb + w32_release -> w32_rel + + + /gpac/src: former M4Systems directory, source for the gpac core lib + /gpac/src/utils: + former Tools - function names: gf_* + /gpac/src/isomedia: + former MP4 - code for isomedia - function names: gf_isom_* + /gpac/src/odf: + former OD - code for MPEG-4 OD Framework - function names: gf_odf_* + /gpac/src/ietf: + former IETF - code for IETF SDP/RTP/RTCP/RTSP protocols - function names: (or gf_sdp_*, gf_rtp_*, gf_rtsp_*) + moved packetizers in this place since payloads are quite related to IETF... + /gpac/src/bifs: + former BIFS - code for BIFS encoding and decoding - exported function names: gf_bifs_* + /gpac/src/terminal: + former ESM - code for terminal module - exported function names: gf_term_* + /gpac/src/mcrypt: + unchaged - function names: gf_crypt_* + /gpac/src/renderer: + former renderer - function names: gf_sr_* + /gpac/src/scenegraph: + former SceneGraph - function names: gf_sg_* for all common code (base nodes and graph handling), + gf_sg_vrml_*: MPEG4, VRML, X3D related + gf_sg_svg_*: SVG related (maybe laser-related) + + /gpac/src/media_tools: + former authoring on media import/export and IsoMedia file stuff. function names: gf_media_*, gf_hinter_ + + /gpac/src/scene_manager: + former authoring on scene manager. function names: gf_sm_* + + + /gpac/include + /gpac/include/gpac: + splitting of former m4_tools.h into dedicated headers, and for some other modules too (media parsers, ...) + + /gpac/include/gpac/internal: + former intern , no big changes + + /gpac/modules: + former Plugins directory. + + \ No newline at end of file diff --git a/doc/GPAC UPnP.doc b/doc/GPAC UPnP.doc new file mode 100644 index 0000000000000000000000000000000000000000..10ea0726385f1b5571ece395dd7a5fce640df8b0 GIT binary patch literal 81408 zcmeIb2VfM{_V_<3B%v(5gSdniB!pf>suTe!k&e`mY>Fh=kU|kqs!}X~3JM}1pcF+! zL>`EM3W5}oCW2H&P(V;DfJ*+KGi_%!SqSQTzxV#%EPOKe&fGco&OP^>TV{54-)BWm zEqc4`X~pZ)TnSKaX699bEc^Wl&o$zO73F2ZesD80GgEfI2rmKA+|U0=4P0EhRmrop zK%k;rDY{vdsQ48@seVd`qV&37Q3@(U9vSk;nZ0NBst0X<3Ivu^B33KPxFs6Bn%E9! ziDYILGWYok8wuXi0>OHm?a|^|_*PpziJDLpAb}tBo!M=r1y3uXDCKF!#_`GzD9Rhe zUn{AKx$Sm*DJ`A%c3wM05sR76Rz5k|hLdhzdqr8pi4z`Flp(}-ay~`O@-gbc$k#i8 zvESEL+>Z~2-VOW5kVmzFj`XaYK*Z+uI%YPXABEjdo#NPfoW+dGB=VOTL0{URVII`6jgb zV5NXxA;m$cKwy!;JIy6G{eQLw9*At!+L@M-lHyKHcgDI?ojoIyBOMM$J9nyUggZ6H z;gB6>iiBjRdPYK;Gsd0la;C?px-;V9ok{MPj6_#jgtJGyE7j$Ug7gt?=ZL6LX-;>n zGb1e_IZhSr)FnhX93v9aD9T zo$leTR5e9PV$>*tQOPmR5ebQj&gl54&{Wh5s=N2$f2deo8{^&K6R ztX>*)#6v&Mr|&uHZ;_T3P}+M%jrOuC(AbuGpxI#Ps0qM#+MM+a^mRhzTCW zrHpYVyMw#9gS)4=q7!1NS7$=3cCl#Dr6qI(2X~Je?&{gILz}c)oFs=u)15^P-E=Le z^{(#euIV98YMUC3aSj=!wgs)>r(qb0?4t_F%4}*`>p(TxLhFLDI zFO^`sIyG0d-Pjw9v~>N7y=1Bt+dVy%<{SK+s+*S1cz0TQG8O)Oa66hKZF`hcqEZ2( zLAz)#d6BrD;10<&Wmjr&ZADlLPsM;ygH7#k4;PyK5RH1IZ zS#+aG`pcTp#M(;rSG1yu`P(|tF6NFkV#)n)>7$$5jf2qI_spoo#3r?7d9{XAQqaAm z;&)Wm0R9N(&C|5SPrr zptafy#I(^m0FM*Q;#`a_LhCk6CzqO$oGhJRLNe|ynT~>sRvn3q8-^!n9y>PGounGE z!(Ld`4{!`7t z$tliPP3dr$L9*x)*|}AhRu8o8<{a%n<1y-m-OsSV#b_kEZstCxk93+v>*~1AMY={>u33QJR+h%+NK5i!Q`Hu~@lO=Nz*q*Lj7pmF0E>|yDhc@9(Jt*Bxb#&fKDz}X* z(UtDf)7s^TWXJG?)btF-$!ayYlWonXRZNUgAn|?SPNNp24{_$s(D%V>+W(54U5UrhP=z_ zU00fh@=85fnoo@Cr^20CYT7Xt<(Z>phus)-Q^je-$izh(E^CfFI-Qa8+j(t?FNE zK&I=~qBckA=;lht2kISX%t&Wg?V3ZPm`7B%Y1>Puro?V~Bf2x0#`WPG#e@3nJFq{j zN$Mq9>sy?3E^6bIed-lDjS}eNJF3V%Lh3}uoyIzY-Y}g})O5OYM0}LGoH4{D$Muzx z5wcPtQgJ`D^%NIX5`}h>YpSix=zyqLqsV4=maN%_wL9|^JVx*IjFIx~FXRq-Leu4S zh{UbQSgg8(fL3K``cyu~sWo!r5{#CpHCfG=)#-Vvr6u(2)Vctg@XY{cGhBXM!FcWwj7K;95OnQ#wMze^wfI-Ss2lt-MU23$~7xZ z&cFq*G{Zd4I8If>ieDmEt!>_JjG+%=v>}F9zh~)IX#K7c)VtP8FjZojQk}%%8M9dpF@!l6eh8nR*444I@!icfJm z9W9CKOS`x&eZQln43f0np6QNZ0@3=CuQokZyO$C13D}_8yj{as%44QXJIDJo?67OR zyZ1;e+ww{ln3&VD)W&%!u9$yg$+8Uoa#%9mIfuF8oKdmjKv=?(0b=!kXIZn1KyzAH zIq~0Ai#Zze=CGV;jGsLN5>GcF9hjq~r5kI4QEDwtPEqG;|DJl+9BxiW=6O4qqi)SJ z=si;oJ(RW%6q}K(t(|AESS{-oV%pS-I30QtUn?qlrzSld>z!iLte%VKwGOwe>lIn| zvt*p8chTA?MZG6LRm*C&+M`7|;}VABY1J;p+H*^9(T#&=(Du=aTmQ@bR4A-*AVCga}dyNTqJMKvsD-N1Jy+4&fm^qEpN@tlr za}xt&W|&k(}N}Ut1g%#!->mfq|U##1i%lGC9~?TVl`;FM9B9X2H$jFv{gSeYG^BX&5J}?LNTG8+VG*4>XgR6_>}CvaHAQR9DZ3+o$!k*s>JrPH`)!}i%3ik7 zo~C6q2(Nacw*_%*`bun9=C)yG>y$vaQf~)T&=mPb{_83BYHU<##~+NGex`NCX7B*OQqhK(}L2J zWYNX+lG;s6>q3wxp*oB+XFQZ6)NSh8&$(6qPk?+meJ_8`Yy0 zO1q+PT9Wswggi>6twmUK%C?fT&qh_io#bOT8oh?HT8&;svUV%$gIUeSNRY)k5>gr5 zc^>Dvb<5ZD_ucfp4Wh@W6l=Gxn~B_tN>)4kym>7n-R`X;+k{nL=((lVU7qLar9aNq zNp7w3R85$%N?|%`+IY4J%}J1PhPj|}N=;=UMm;l44BuF~)y`;@8kdoTdok-xuY9eH zgQWh=+b|YkD;k6Nah__0j?y@+V7bQprlbSdXfB z+giQsVog?mhL9c)+w9X>T^;9n3r=J0+@>q@GP7QRq?I01d!SFI9MX=|Zj|N5H2Xt? zcO=@ZKwAsZ^Rs4TpSakwBu6GLwu>>^lU=N_N@^WGn*F@jbvRukxlZ-&iJG_OLba@X zwW#VI4Oj-KT6_5`^32+?H||^IVy5(&-yN8QL(+QREzmE=?18j#mFP+usF}a4di;Cr zNm_?=KGxJO2Q%Aq0(VJuZ<-dJqCU8w-snq@N==uQ9j)QWay1eA zjrwjG$yyg@eQcs@vSyO3R?z$9cyOkTQ?hrvjMS`7*GQ`S+${tkjb4g@^vM~8cR>cO+R^Dn+}A>`kB2j ziBTWHPhuMtr>@mn8XwuXQ+(ticO!@2Iu9mqKC-YjUbRI#@`|rj?;WY9a9^0UF0ab( zLA8h^kbL@Gy!DFJ#&(Yt!n(_ACh6 zI&e9g6(98}M9&ak>fc&ukHtwl)U8i*z11z(B3EEO(yyn|XT|EWxHdXh9kbq!JwtQV zGaJo8b7fU7n-u58B?S{v8hm--y54Ds+gbWHj@z|-~R zRDuIHp*>hHwxK;8i$&0{*_ESO3Ch&#MS38;chhRuQ+=8;j0ufR5&9uR5>zltg*1 zUri`|qMn1O$==6xFz$z|>j}D2sWiPty5It+40RT5^-sDyIi#m#;A)JqjV^<6w46_c z8i~5Ipwi8ik~k_%8?BQ<#_DQ)TPs{nbLfQ;4e^+SHe@4_cHdlm96`VIAugUUj>9J0 zXwAG+;HxyA1!;?7v~dr`Q6~w;;9Qe$3eC3klt>ndMA4~oWnzlzQxh_9(bfW^JTnvZ z!3h0pE<7x&J}Rx<;nz+!2RgWJd`7a%#TQ|CAPMoQa^G89ztSo%Egm~kpK*@Dzmlie zx>J8Zg{Gw`CM}$2V7P&=mQYQ>llhu-DYKcOc8^KisqA*gaKm5y=94vvT46Mywj-mG zQn(SqDz5f;fH)W_Oh!s_ir%S_g}7#Yu|jnX5$@zR>N*!U|D4TC#}}sge0mn`!AHkv z2f|zo9;%5uGRAY&oHd+bS`udqXEh!tam7?~HgQ(de0NN>>a-+TN7fTnXI}0!1X)+h z)bGqVMV#LKN^2ul%~?}@NCAJa#4UbS zEyEI;>bct!tA&=-dd*Q!dOGX6imgQ2wdrDr&s=G984Za<`s zk)$HT)a{34k62>Pb5=Wi#szjc=KNL_lu)Bt9jTMCJf7ijj&+RH1}(fJ6sEZN7( zV>a5cP)g-+Na8^e7oRCb9nJO_QP?ai=z~)3lZrXv#xs#A_2*15In$Qfuy}6O*szO|@|Irc&q4={8c0 zp<&Zn>aM1SuhNp&@{X$Wrshp+S!L=4ReP}>a%+atT9=CS+~o3mMWq@U$&ghV2BnZM zLp7~s?x6Vg(`#juLoKPl=GCZIy&YSJwqc>&Gg4fsJ;>2$@S>b-wWrG#_0eKHpWCF4 zs9jqWZt7HRcb>D&Vwqzgi(}F%PaMfuGaa?3O=}#E|Lk{Ib94I}HNYDQNEzYit!t{Oe}=F&Hp&i!iESChXwH|tTittyI_h;M)I zM@q@~@dZaKN$vB7q=91Y-PkhJv$u4K_`2O^lD1XnFO=FHi+GL{EEzv9sF5em`I4rj zn%=B6GwiM`>E{YBTqXbf34@+;suOcC2zR~tqk(ldX6oAw>4FRknycM zI+Z9ePpB^Mc`@`~ny~0U6dr}qAbPdxPV^=^8v|p((9=o6m*F=Mo&9Fj!%sdVmwX=a zea>0yIkt%JbBZmPr{p+H<(I7N*CAG3CK4B;Dn8JUkTge> zldr0hzg-@Q)6k4~fGwqVj(IlkY6z(87ggC$msY~CuYBmN7?gy1P#^kQ%Nd!oi2m{t zEwSw!>-oOI_Uje%wC_=`W~rhKjS&e{O(~;x{AagQ@*FNr?I_t1{CqFJki-3zz~?hB zInEXJZ|S;`S~El<{c^{6$kPtX$T$NtHet|+JciXE1BxMWHha=I=4Yd~1F z5)J)I{TiSsrR7iA!-eH!E9J88DxY=NU0HY4KOCg^`zt_;I z=u>p~Ac)?4+rG`hZIR~E%To?*j)Y7f!byX zcRc>jBf2)m$JNt{{M;jUmlqo&4lMb^gjnag#B;;ECVF4_Jl@P)!eoI3cs0Po#v+z93hu7deSPvUuBfJkEKrLpyZJ+~mgig>Ixm-D|YKL5*H zukGqzW_k}wnXPGaC;6++*4QKSE>;Eg*_UTVm}REMs-SH~n9nkgH0Oab>oX)v*pkMa z=^1IV&MmW_Ga6;fnqH0=dmD@d>2me|_w_HjHhlPNgvEyk z^?yEB|Nlt;FS<7R?7Im|pS|>dK>ss>a_v9sV*j0w|3%j_CR+nC7TXLFjHUkD?Y}Yi zWODug-}nEbYh&CkW9^4v3G9Nu(gti}KwBgyg8+MPF9TKk9$69A`u|h8`u`{Ve~{?e zm{-YM>PLuR?)0~HpA&UwNn_Xct@J;I+ugbL{}0$dx|aEJOXv*U;Z^u=*MDuTspS0r zfA0Ekw(GyLP9nM&y*~yoz+zYeYv3L5E6N-Z3PEA$3|$}+(jfz$fR|t{yaAhF9~^?? z@HKo3=inwN{94Eim`gpK2}Mw7RVKWi(-QDY56?(o}>c=j9}`G+RSJloh~p3NP1?QHpL z?q%J_J1%EhkIT($GmaFAYfqn)?h}!M|7| zSFDi>e>d{aO8fRN6vuYXUy03*(b-*K)#otcvqAK_1Vp!MLG=3poPyJE3FH^`{)9{j<|pi`KwYQ@^`QYY zgD%h)9)^CRRgcG@Jn^KlxV?Dnk{h z1+}3qxFH25!b*4pwm>O<39vNW12)_LH%5N3nuN^}*pB$NFPpXcPG)_~Qq#YRTWCCGnE0e%zFPjNVo7oD-;I|+6cmCwzeTPqe zdh+8>PrkQe{tHh}czVAp&YaZDuIpz`CO1I*lc(iFsw(aG7iEC+X+Q+xc5!*iR_GjwOD3_;yGRkx3)=)=$v!P?F zenq#2PDP(5(Ua&+bYtkCKjF#n1T2NdWqEEJ2EtsJ2S?yntKa(3XT*21i`H|#wnqMn zG}}48GyQ*(?1c5=ZW~s8yE@9V^##(Dv=N{uBuyln9;39_P9Jy}`hn;)8WLbAWPs>* z35brD!#+3w)zNKDXb6qK(0@n5kuU(HEervpJ-kZzHTW0~gS3yYAhI0xSf1}0KuNe4 z+Co?84+9_p9)YPa4c3A56JHG zk~x!aQKi_MRHbRt*rfOcn@wWD+Biy5+K!Mq%RVGZwVM*LU~QymwP0v_$xjFC{wWR)~zDt4BxzzJOkor9U2jLKux{G!KW8o!GD&XTG1R6jzjDqd( z37myuck^8kh=RxA-)L(#4`GYg%-H5TY{~w1#3tHz#CJY_HNR%w%)z5U@WBvm$fnn#R0%@UfDvbS%W zhw|->D6e-)iD&gu_ei~tg~vc_bTe#$?U3KecpvVDd!Pn{Ltl6p2E$T#9k#)KH~4A!)8(IH8SBZ&+N^Er$rfkyd{59)wSCCwN*isP zV{y};ntQAxb-thL(YCZ0n+9*GanE^X$+Byy*|&|Xt<~IPv@Tiu_T*u0{WT4p7eHsC zYeT=U5f;6QE=7-`KSO7tm(HQA+dx+s0@3g-oP%HBS14GCIU(5mzAa*N&bEjxnJr>V zW{cR8`HuK@!M=~!@;RqiKDHyiBWEn9D95c4+c^iVM{Hr6haXxM7pwa9UyCttQs@0z zNWLBHIVug+(i7NZNP|#Hi!Ggp>rermH3UPqX9;`jbTax}0I$MgI1OjuB3y!>;41tM zB`V{?p&ZnM7SI-$t9^6r%e~t_Shw=km!5m+iP7s;rX~#Bo0_nJ!GFwQcGJGOV-Xb?ZG@#s>;j(E78))UaOVJyh`%0OUt^)I8S;X zQAbJjuPL7^lD*crEq`yHVV2V7NzA>XKvNdiD7VWkD+gven};J0YrMSJXA|fReL(ap zdffsiz+1nfThXgkr^AS+!YgnQEZ0Fb_zD0lNIo%ctlzUs!oa{3+Y3Q2usv(>8N<+=o1K3ijGF9o)gzVC# z=_w_}9u57?CoDRA6%0KFqsI`)2cpvfFc4xP4o1SGFdD|dICui4z%1Ae2cd0M#*Xj+ z^n#z@D*OpIA-Ed(Kuw5%M$j0NAQ{pi9cIETm=Bxa1K0(h!JlvwUI}9j8h*L-&9MVJ zwrqHN!`lZod~;0x5k0Wun;pxyEIPJj(d=)I?bu>)Z2A`dPv5afG-KM1RI_Pg=3Z|r z_Kw@^)$~55zp#1}>@oX1Y%)kCXPYH4Wy-mBuO#QGdpJj$jd_k)dh6bXR-KCew!tT` z0}OrjL_ealp^ykqz(QCD`{6Qp>(i=BLytB?x0#GBa^7kiwj()=*jzvk&#`6tS0cXi z$zgG9nfjJyOJ>%TX9N&py({4H5?SqE^$leW`?{5FiA`mKUl(%NDfP&7tN#n zKpFpew62CiZqXvjik}o6z6aajCIoruZ2<9sFae%~DXu0y_Xp8kPya2Hg7iVzCd zE`NLZ%gdi{|Ms%}{~93!2A%6Z_~FRf5Y?z5PCIJzzE zJ+Gr#_sChQ?=^j`>@hts9@#r?^YZ3dw!NHX>tD=Ks^R-h`DU+R_5tP|BdyF!C2X8i zU+mJ*t?2bt5Zzk!YSpP#pQ6iIVCYkHY1N|(J≫r>#NT%p-?K{%4Y1^yx4Dio>ya zAFE_*I8erq(zLv1g6h7ITiAaY(T&)dVOuu{TWu*Ed#VX_p*!?|zAy|@VFJ7ZYvDuq z1%8EcHCej@o7!xVU#wSPyHjtA*pk^I7pwxlwMI@`BS)+e+YwvDcd`Rk0iRkUwj;KP zEtxGJ-^o0ZZ5pe3Z-hS5S3|aAn$A7imykFMYdesA;>axP0BU;?_ob8)e`)Br4q?%A zH!$>U=y(nLM9*76^!zheb=?VFN9sBs%+?JfU>r<r@b1%Nu7RPhjWtk~W z&o9T#z25x=IUD6N)0i@|96_cu1+U)2t2YS~8x?(tjtsr*BzyuIQ}>3B+7liOqN}Gt z^d$P(1m8lAUa9ChIx2h)uL+j~B}I_nMby-6M_HK6jS}YqfD1^+^NpwsFrsX^3_i>YkEfUu)of z5M4GvZ*8G3h(1M^TVXrwgDdbeT!*5y8RNr)&IdAQd@lVhCAA4*J`_ZgK_KJO*mW8!t*=MGfb8M+i3zj2R8Cg;W zX;!Rozd*}b{wnNMw_f(Cu3f4=szJHcUS7+vcuyK>I;xM7ai4mY)$duu#+B6)JGJW0 zsy9PtqANpBR^3>2V(4QPIynfX>+%i=Xb84$-xjg;=eEcds}b3HdYeeFmp4cW#7YBN%Mcuz>3{aa><=7^!R*pTRK ze>QrHLwE6z0ApYtybNDLKs^cod7w44fqC!>EP!3G8}>lM`uG&+3M1iBcnW5~tME2_ z1P9J5eEYpnp?1ybDdX=o+Ky0{c zN4|^+1470dqP%?r9!gYf^Fw#&q3Vf!8afu;9?|vdtyil)_oCC2Pz@c0f#|mpJOuGD z24=xKa0qO@{g2jGZHw5F*&@D^*^byEHUYMd*LTD=T(Ft1En@Qwwj;hH2d$T#!-(}1 zyZuXp)B1lcB=)R@WF+9(r`f$ZE6D06N{fCjLji238dL|dEwQI*FdY`cM)&|W!%p}V zK7&k98sZP&E~o&Npb<2NF|ZI8!LQZ}@*VN5#`9JIwuoVtGZ)SrJ^b0>ZAUk3dsE}W(G6!_XZMAp3yyA>J!AHaDYIW!Hw!LI(CQEW zKC<&Q&HLkHZ}hW_;5a66`>4v?L+Y7j%X)l0sdqKms--qPu~f9pN1J0sIbt|>`7UFY zl;#*wRTg7JbxW?cGtJSSalZ6tX4pJx?az#GU9n5igVg;ju-3VE9T&NmF+Vhg7;r%> z#K9=|9QMO0I1PV5ttMXMKbxKScEvV(%waN{XxpvdzY?(xRDDOjG;NT8Z^!;w&XU;# zaEfZz(xfyi)%}ywct_=NFC)@3)&fL#R-L^;d_Cl+ z-V1=}unvgsL~o+A1z_lGDPhssY7o8Mu(o|${A=A&Fa-=n4K>vZP?X^=*h6H?+F|B z)xyih`ZQy$5LUrz_ztc?tL8jE3e(_CH~^hn-~-?l_|?1s0yal&i~Jjt*&2~e9Ve}2 zJNjQ7F^Z;YzV@&IN{Ao70pgdxoqV5H;_}-UMo32ep7FohI&5u1-BU*Vrs#7yI$8ny z;BzQ@KXY%W0WF{Ha3)IpcD&N>dc7uyLy@o1jhSS8m{>D zEm&!|pZ~Qym4^EV)C;aOJRopM{wBThEAm@Q@`Fl$`xlSYA3JJrIFI5N(6=C4KmUMh zdD!{~kRRKCz*ZYXKT^*BmHHh1KT@B$<@{&uD7QXy>yvd~W*G9x(bo87 zyZ?xv&uyQ%?K6k%(rCZA?K7Kk-GA1ORA-X=C$|Q2Yaq7Y=K1)L{ zcnl03+$s$>HIzZ^{Q{HP7YIy-G)M<&-7Qh)kD2~#3rI5c6Qp!e+)ApFq(mu+>>(T4 zN9&HIRVh(yMUo+9pyJokk2C{S3F;cS60G!45|nggxD=;Shx1F}=YlHx<*Ta59kXIf zt|-NqG*wzw<*7BLLCE;l9i7U9?Va3>@#k)gztTTs{6IEQ?CzuZtMdD(^5ykid}G}v zpT{PZ!ju5{9>IQ2k=sy2m$!=LnNCe|dCszankcOX|CG5%X`&R!W9%=YL{bxpTuZci zB`MTMDpwSve5b?`&fps5(@RNcc{TGLww`kfQpPA{2xq(0luoZ&Ew89QI&c0oy!m7C z>TksREBTRIR~hR3Iddyp#Vk_+r4{)`L$X>XDP0=naFO0$DImq+GenuIyrTs84N*kT z@*;DduTUPK^a+$m%EWVGN|RoNm12i^#5`wf3T8Tg>YHa4lz3{ah+lIxk0kd~>~l~D zQb!5qwL6ve)I?{c6G!u-i9i$_D38`Ekq-t07N=C=lPfCo&Zl(!gHU-CT#RkM*6!qV zS91EG9-~rRX#*lgCMCWxbJrsu)h^ujx5+mr?pt>xbwk+FBYR(ccEH`!e+~#5l{o!K zrHY;J|LM28?u&T7sQ={T!2P>7{kD5q|GT%hx>Tp?x#jy;zP~Tu&Kuhw>iykkdmbGA zR?i^|gMzyD`L0scO{?B|>(f1T26ub)wI1KSa&Obp&m}%vX~|c?m6xw={>+xtr|0J# z{NBDr|Ef9dzUXFkipDh^b$-K`4@(XYSb1(@(*^C@tUC1da`&_q^(WPCoIiYF?25VX zY?#t|gY&EISEonx+mZUv-fx$WsCYa)@8vaf&zJ3Scj4=fcBgBHw?6aP)e`O7O~3B? zw%+F-B+cKp{n+ua3p?Vz-gdF8vNCh(&As)no;*B=s>sX?@T#n(hhIOpg(D4d3DQso zrMeQ+YDLK3NzZ;pB^7w`^5jhuKOg(h{*Ovm8D4AYjMlXlk5x{GJsuxg?pV1C$GUzJ zly76mq$QVsTi)#Es_EBHKYz|ya_)+tkIuAiu`B-c@MfDIpRjZClGm$*^c$J-#NyG% z-W~LQ-ruq9vHC+QKmPj6VS~Q7`^8tv zoNCzVz%M1cebH#}s%Mw&%zWpg+Ph!ry7lq5!q2u1Om6gir-W~YELv9U>+YLoEOV_m zSYhA0>#raFlS|2Zp+iT_E;*44oCadC>G7^4S1rrm&QZxxajsNp9tC!H&i9eCaLdzU z7mb+lWuxegVQq)3*|lopuS)Be%eMMt;r<23zBv2!#728h7C$uaK}X;4mxCSCTzev> zymw_x`0M4C9c^EJTX^E>PfC3I-N@2A*FIhBWQQGT4~?yKXvX9>-#zX;{BDgy6)%S$ zANa4zk2IV9K=1Pheye__?S&du^Z7Tf zd~>BA@9H(W*4xFZJ-xU|&x=PKYZDe9srmh|_wPF~KX!OrgL+-glzZga_U)%kXdF4U zT>Fq^2Rruvbn3H3!zP6OQsYW&?1)Xpo-OxY;If7Hu08SP$kT=7NfuWY1sXn zTJO#im9Xor&E2mydpRh)a>Bu%+yx&kb$D#o_Rl{tWliz-{>WSM=Gi^(o!l^~Va!v- zE{-2_Ps7Mv&o15FaQ5sr%173N5b}U{xV{xT@^Y$%0`*2cH^;VUC z*;KsB!r_H8e{K-Au};~U%J1_g{~9s5dbjEaTeciE=)3LzYCn2+ow7p{M@IGzsZ->x zPdBx0)314_;%gTBHJ|;#12bn_dG+iUKQGw4c2q*%q;Kx;v3KU1JAV0jP{f@4lY)0W z+NFYHSBDFm+Fd;}eEFb&WiM~b*m%6ldjr2epcD^0wfya+E8h9M-&^nHpI>6e^?O%t z?B4Iq28m#$L!W-rmH(|)L7SUQbgzA{$@~Ut zq~XNN0}@v?NPItN+w)6;>&2JYH?YIt>5=;fEpSdNzrNwRGVgC& zGt*q>yQ0^sN3$?Q}^{LVINkX{mP@C6s$e`O2)jx)4v!{G^Og1_K&_d z^^0~Nci1_uz?+G4^Ie(|c&6^KG9f>%TmR*zv+tJ47`5r?LP?c-Ig zANmFMJKcO^xvwhEbnUO->fpROBR>8qUu>_NzgA11v^u%LzJqTLoIm5|wol(T{)74V zJ@(ksYh;pn=N?!!B>Vy#qWD$S4_jBj~<)9`*_B)Axp>JyXe~7edXMKL%SZC z*s99w&%V6A>10=(KYF}Spje;vQ!3T`dRWzy)$0E6N!Y~BqmTFQ7&>$1Gn3}j@q4mu zvx^7cyt4YoIo~e(*NTD_UrP(AJfd&>6TJ_n3_BclD1K$=*o8H#KKxL=lJgVK4p~)v z%;*<(e*fvR$#E-(9!T%LHnzrqUd1o8zBh8vpohPO{$G`M5kkXKe!o!e{Z^w&;2w9CCJ;;kD4$E}&&VnTGpAD!xk%#A$OvQ4G+ z;rS{z>N`5N=J%oVAN?vluIF9J5#JVns^|7HrBcgHJ@Rqn=1*I zq(#b#Kk`l;cP!t4ec$`7I$ZqNjTeshyV|AurhWSx*LxGp{XdnNQ)gnt z^V=$)AJ*r$jLYK^$6x3>((%nldEU9X;Oo}EY+iov;?{E-yzF(X>DV7S2)wUQ}Bx5Rm&?}99?J0h99bqDz|U_f$MQC z&XuVD)WHf%A9nYuR%1?=?g5!UZ{JqDUgL~MYAyQdy;Ga(zuo`%>nj(`{Nl{EvVAk! zY@$7PJ1=$pWm?tnHA?Tp4e5}KoU7eqAHoxcea~+27UA^tyGV>m6(B{|lsUPlJ*7(Wu zTh4#h|4^Za5=RF6Z*ug$8U0A}&QlA#l73gr=>BnE%$WS#AJt04Zf(%_^}V(8bvQ7# z=}+xP_J6rW$Euz3zVun8Z6*6Ie&NNAYrCav%ZOi{C++>B4OY6UzdvSOO7%r?Ps|>W z@509VbNsJ0p4})pV{O3u32U|w?b$z1_xgX_^L+Zv zkJGE~dddH%*kXm6yHf)ncvZ@gZO&NJ)S!14Kv1?xCcj*)|;u#5_7 zX#*m4k7b0Q50E=NLNxw}P5#n|q*id+8)#Fq4y?HQT(l-qp4O>)x=;9^Es_>AA zC!;=iDPiNB`8$h6*F8}uenr`kCf~gi^%tLM*{x)ksbAg~vwHA^XWWf0m57`9 zU|8p>mAi#S)Oj(rV6~3Vy}WN)kL%-BHD3H|uWv#Zzt(EU#(nL7%NV=x$9aBZwpHFV zr10oNN}1V_b2H!hvvJv}akcI)IpF3)tdJoAwCzfRBZdHPJ^?OV59v^um9mr0S zI$H9U;oS&4GV12Dm*y5tBJ#mJtX0S)D~~dOtFI|zYNcrlMrY39uGF*ycXG4PIuW%) zov!3)cT7TZT(i)gJ=)c59O_IU=?#S0Ps!4QWYUijFCjyew znnX1VjZaTcX;Q0JS~TO=sI&-oiYu98vF_BQsC1&KakXMnqedV&DX~`F+O-?jN{UKI z4s{NRtJ5qrF}+TxGkqkXn4yG*#MPC3b!8u+n4yHCqNABAkwOm`dpNG`G1JsD_S7@d z)Hn9jH}*6z_B1f|G&J@!40XmQCL|B#iewY&jCCir*LE18&{{ly%$&H1%mx*nVk>~{ zW@gGX&!2jgU%i)KK9gU+kzc@&UqO&Jq08Hl<&C)VR!n&_p1d6?G+cWNg?v+1zAYu+ zn2@Jt<>}W@@~8qNQ8*-DP-5=RHz$B33J+5%ErFy;8+ZUZg3Lp^z(dd-dV!S9kFwQ= z&!I{IzTpZtUB@{2C=R)2Z3x4hj| z-tZ`Id6PGN$=iP9jW6=n2l?i=eEUN@`&o$s0xMC zm3sgY3L=yUK#Wows2*7(Q21h~f=KyNAhUbkAOTH56w(S>LtAJE?V$ra2%VuTL_#;{ z0X?BNaH&_MZdpILBCCY{tS9)h#Y{{j-cqR`KVXTj`J-ei^Pe(aZZ^6pCh zD-{TCreuYcT~a?xDgD8 zC*gOHMV^r`4L*d=p&$U*P4ZGnRc%PzehcLWVZMYXY zLnQQpzAzY~APq8LEIbC2;R$#N=D}iE0xRJS*aVy56W9Tt!6En>&cOw^2-n~`{0Xw0 zkRJ*_Stth;pc2%EI?xL4hqllWx!5e z1XjcM@GJZVzr!g^@d8|g8xVkt3xeWM3Ti_$XbxSVEA)ci@G!)~PT8IN01-BdkFf&tMC@Q2Oq;8I1JtBF8V-Mg&I&F8o~Y076yX+_}wFr0b^kb z9EFQeh%ToD$d8^4fVr>`94)x&;SOXhi8ytkM;07pkhozwsRDp1)33XsHOoeIi0?dYmun1lU z`H_&-@HV^$73hlOM?$*7!w?6lpp>J%LqRABl_4CO!2Qq~I>Lj{6Z$}Z7y!{Q6w+V} zOn}Mo6g&+JU@@$OH{cz3A2z`!@HrfXV^EK7znOIXFdRm}SeOh?!)$mN-iMFj68sFm zKrriS10fdTAQ{{+97e#SFd3%6Za4^o=_2AG5z=7{OoAui8JG>Pz(QCC>)->}4Durh z`{5{@flF``g6Qfapdow!JHgLM-9kACgZJQL_yj(KeeeaGfN$YvxCS>Ns3PqKN<%1A zg<4P#nn5dA4D!5jDtxq9iD<0Kwf(MI;;kH`SDiR2HRmD9Dy_N4SWaR!xi`$u7S*9 zi-ys+Koy99hR_&VLL~Hs74SA30eP|OX}Asn)v;G-3Oztx92pC47!9l71K1Axq0BwB z9gr7<)`tX0g-2l$JPmW#z*ofH&b?*bF;BUcB}Ibb!9l52C>ZDUb@IVG*nb zd5M?2ylXpr3K!rq%&LVifg5lW2GpjVfeRAg5lDhzFbcNAPAFOj-9cHX0Cz(*s1Eg@ z8MK89a0C7Xzq;5P6os--0qR3DXaTLE4fKHiFc>N`SBQXC5DC$c48vh8Oo5p&3+BL! z@G>lgRq!MH0fF^tm(UL6B}0+W6MDhJ5Z^$1Y0w0=v)~1o53j%ycn#iww_zQuhxcI< zd<63H3whbe0XPE3;T!k?euf)hybvR(A^r&*PzvOw81AfV-gvG=YxL6?#A)=noS>UhHrPj=>4I3`HB$-$E&< z2%!)L5zq*lLQ9x@FLe%cVKMkOp`M{U)ByR?e?w>kkuuCAfvH7%&x#0%&Zn(1X&eZ1Mfnc z5Jp|F1XjXXI1iokGQtF7b<9{5GgiTjRWDe4+Rt4qBg0a9QN%m-st=``VUV5}Y)t3}4@kg*zMtp1p*JcYCs7FkvK z9c1-HR!)pn5@U5_UQtGvAgdhVAgdX};ShWYAtf0hgRx3stWG@2zQ^Db*agNaMe$P1 zCc#*(FjgtHu*W@^fA?%a$3o%%Tf|%$jA!>}z%`v*Le&F)KD^!!p}#2Qs^LgUn`U!&Z>lt1&wr z9LA~@JOj%>W}$0fEt~|Ih28*}ef9*IZEgmcWmW>2U8aG|Ccl9;H5hG!%n~EvcC$od zc4*8BjoF|v3p8ebzGivGtnM>ra5o`<8CZF!1Px&fEP!X2iOm3Cvoo2EJqMq{UNB~3 zGV6*4nRWdR#;nVjUDahK)EN515Eu_n!iTUEWVZAt$Sg@_NHPnO8Ia6+-UDNH^F85< zAhQ~|izBm^4lo`jfiX*Yi|`td*~u}G*+)|AmuJ@JP)beV{2w1?|-Z+)lLrZ|Fr5z?<1Lo3M(6HTrK+k!#lQT zcWhMj_)(Ij0gVHTOnULADqx>K0vZPnCTiNM21u9xfw~T!x?W`fWArWn4*9hT1&FmGqVoeA{b@EMs0vWEq-RWEt;k3DISgDy+3H`D?VX61Qk$7T@Dh zv+0FqWEECM6_$Ntv%bR(H)0j2`=o3HYNeBwr+Y@T<%wrBeUep}ZjnBPW#0t<;-zNa z7XQYjO2gDI)ohr5`BJlQp?~pGvu~<@<5H#F>X&M^+uL1gZUZhfDYpT8##C0r*9S-0 z7{2C~avN|*&s#KeJ#g0EOY3ZMJ@BpiRqHU-s6lO*8t-Si^LRgoA@P3RLm6Y3iVRkq z?H^4>>3|}WBDE<{=>QpU2Mi|eG4eo8lA*3P+!Z-_>|zv6&JLzhA)1^WfymjxR4T+G zC&-jz4p~K3uw9rYYfDg(NhAMMhrL^ZkhLXfFmX?rLTs{(;j3D<;Jh}0n!NQ4X3qbi z$~%%5dFvTQpZ~)nFJBgU#&A}b$qKmVqsd&IugIi6noMwR zLe#@ThVhLpvZbrnbnRVck!=i%J@Shf;`OqN9S^>tmc4yZJ-N zlaMtCQ#b)xBe2G0J;556wFhfl)+wxUS?{pMt@5PB$bW9%u)v)cs%%Ro8s6)vhIXBHn6K#Dxz2ib-H$yC~d z^5Ox+;?C+tZ_IWpYvl6E0r?TngMIQUOX+=( zcw9+-+;3h`BPD;reaea6o%k8fUW)u8ocuzZy!cyQ{@bnZK&5zktTMjfXhnV#{%rs8 zN-Y+3l60pQ*?X4$3>M?+IF}$nVI>uhGd5h{|sX%Wn|K3+CJ3 z`w>swe5`aU{)sX#WtY;W{66KU;Rh6X9Yb>S(~A63g1mnC?!@mD`GqX`{VVw`f}Uvc+(L zYDT1!cTOZJF5ZUVRJyPo!L}Ru%6lx5Io=>>hM%lxczuk*%kFXVr@JzWbB3sIe&7Kj zE%*FEf&TJQb8nqZ?ydB<9wZ{6g?3JGKwf|UJpO?`&uL8_8R~g1{u-rbsh*NbeHdMk z%|{@ggX+hAKHq&IU(Z>3BF(Ce$T$h~rlyjWINoESZPVD-N-J|<9%?x#fa|2yXI56f zJ|m|n3-nA|Q=3vd+B+VcN@wEfqIJHJ6R6Y)nNnK0B5$i+uBLx^+riiRf0XA*kx)r_ zn10|o>L0)@lmZI(_c$Y^~vxBjrHImCQnZA$~2mO^CmxD|*})#_uQ8 z%~oDT@z!3S!rVyqbUo6KTKm$4x-l7JoN$VonQ7}iIin!o5tH||Br8t7DJE~PX~*9T zWjO8Kb(^DJ#ZjY``7348%2fc%Er4AYV4zfhwqF1XmjP7n=l^02+@zli$d}b(WY4L| z3x2xZHNNo5nITGzYVUkmn|+BKkj_euPXV#O86dsG%OEDP45XoN0qHw;0}fX?1=3$$ z18MW}Dq)!pgt3(tSf8y7(p$2Xp?4>?jOCObY$ebBY>TmtVJrC-uEt}=Yz;H?4$C#Z_BPXU?lj{{j_l63*Oc{2m#PSJ}XD_#ph=GL-4AoKXu zP!iUI%=@>1$le3i`MsippAQjRe9Wr1zjDV3a3Lb^gFb2lLWAHePgYhr{Cc-3`3{Sw5AZ44% zb{b5Fr{HOL2A%~uK9lV%cn+S27hpEb0XhDs&OALX`-I%je@6|-v#D-cj+2(3%r;eR zF(@mCpOQ)*KjTUQI43Btzk22t?R+sM^E36shP~vum-*}&r|)f}KDilXrn%EVKE>b6 zU&@h_^ZQC7abA4tV710Cq-lHZ>~BHx_v4fx$Z7s^wISk6`1GdsQ?dLuY~}aVpjX)m-KIWYK*Ga*tKZBzw~FKW^3EXsNUQ4f_lAKSjjo z^`9rpmET!;8k2t@;^f-pleL6d_so!8dj5WRet9}O1&=;N^|V>j-)c`$dQUB9?eDG9 zT8|C3M*e2_ujFrJDQ!2`A6ski|5n%!?fY}PL$2D}cROhtZQRirN&Kvb)AO*SJmToQ iw^2=gBBZ|BcDmf(u(z0#9EdPZkavmZe*Wug;Qs@VVX7kl literal 0 HcmV?d00001 diff --git a/doc/INSTALL.gcc b/doc/INSTALL.gcc new file mode 100644 index 0000000..a3517cc --- /dev/null +++ b/doc/INSTALL.gcc @@ -0,0 +1,116 @@ +Installation instructions for GPAC on GCC-powered platforms +last modified: December 2008 + +0 Foreword + The output directory for all plugins and applications is gpac/bin/gcc + + As of 0.2.2, GPAC cannot be compiled without ZLIB. You'd better make sure it is installed on your system (zlib is provided in gpac_extra_libs package) + +I Extra lib installation + It is recommended to install (source or package) all extra libs needed by gpac not installed on your system. + Libraries found on the system are indicated as an output of the configure script + + +II GPAC compilation + + II.1 SDL Support + GPAC can use SDL for audio/video output. If SDL is not installed on your system, you may indicate configure to build with a local copy: + --sdl-cfg=path/to/local/sdlcfg/ + (make sure to update the local sdl-cfg according to your needs) + + If you can't get SDL and don't have OSS or WAV audio nor DirectX or X11 video support on your system, you won't be able to play any presentation with GPAC, + but you can still use MP4Box. + + II.2 wxWidgets Support + GPAC comes with a GUI player called Osmo4. To compile this player you will need wxWidgets 2.6.0 (2.5.2 should work) installed on your system. + Both unicode and ANSI versions of wxWidgets should be supported. + If you don't use wxWidgets, you can always use GPAC command-line player MP4Client. + + II.3 MinGW DirectX support + When building GPAC under MinGW, it is also possible to compile the DirectX plugin. You will need the MinGW versions of DX libs + (available at http://alleg.sourceforge.net/files/). Get dx70_mgw or dx80_mgw (dx8 is provided in gpac_extra_libs package) + copy the archive content in your MSys tree (for ex, /usr/local/DirectX) and configure gpac with the option --dxsdk-path=/usr/local/DirectX + ** you must keep include and lib folders under the same directory for the configure script to detect DirectX ** + + II.4 Building GPAC + go to root of gpac distribution + ./configure (--help for options) - you may need to "chmod +x" this file... + make + + any fixes to configure are welcome :) + + II.5 Installing GPAC + get root + type "make install" in gpac/ + + This will install MP4Client, Osmo4 if configured, MP4Box and all plugins as well as GPAC documentation man: MP4Box(1), MP4Client(1) and GPAC(1). + type "make uninstall" to remove gpac from your system + + II.6 Installing GPAC SDK + get root + type "make install-lib" in gpac/ + + This will install gpac base headers (), gpac development headers ( and libgpac_static - the static version of libgpac shared library. + type "make uninstall-lib" to remove gpac from your system + There is no documentation regarding headers/SDK for now, you will have to rely on function descriptions in each header. + +III Running GPAC + + III.1 MP4Client + MP4Client is a command-line interface to GPAC. Note that the player cannot work without video support + + You need a GPAC configuration file to run MP4Client, and you will need it each time. + + First launch of MP4Client + go to gpac/bin/gcc if not using the install. + type MP4Client + the prompt will ask for + 1- GPAC plugin dir: enter the path from / to gpac/bin/gcc. This is skipped when using the install version of MP4Client (the plugin path is hardcoded to + the plugins install location on the system) + 2- Font directory: enter the path to a truetype font directory on your system (note that if you don't have compiled with freetype any directory will do) + 3- cache directory: any directory with write access + You now have a valid config file for GPAC, more info on this try "man GPAC" or check gpac/doc/configuration.html. + + The config file is called ".gpacrc" and is located in the user home directory. You may run the client with a different config file by using the "-c" option. + + *If you don't see any output window, check the config file doesn't use gm_raw_out.so as a video renderer (or simply remove gm_raw_out.so). + + MINGW USERS: there are known and terrible bugs with MSys rxvt stdio buffering, do NOT use it to run MP4Client unless you want to understand + these bugs. Use w32 CMD.exe instead. Other GPAC apps are no pb for MSys rxvt. + + III.2 Osmo4 + Osmo4 is the GUI frontend to GPAC. If you have installed Osmo4 on your system, the first launch of the player should ask you to locate a + directory with TrueType fonts and a cache directory for internet downloads if no configuration file is found. + + III.3 MP4Box + MP4Box is a tool to encode, decode and manipulate MPEG-4 systems data. It does not need a configuration file. + Help for MP4Box is available on GPAC web site, with man MP4Box (except on MinGW) and with 'MP4Box -h' + + III.4 Osmozilla + Osmozilla is GPAC plugin for Mozilla-based browsers. It is by default installed to the user mozilla directory ~/.mozilla + To install the plugin on the system + * get root + * ./configure --mozdir=/path/to/mozilla + for example --mozdir=/usr/lib/mozilla-firefox + * make -C applications/osmozilla install + + * OR you may copy by hand bin/gcc/nposmozilla.so to /usr/lib/moz**/plugins and bin/gcc/nposmozilla.xpt to /usr/lib/moz**/components + +IV Configuration + + IV.0 Foreword + All configuration information is described in gpac/doc/configuration.html, or man gpac. + + IV.1 OpenGL + OpenGL is badly known for performing quite poorly as far as high data rate texturing is involved. This is a big issue when displaying a typical movie and you will likely find the GPAC 3D Rendering very slow on your system. If your GPU supports non power of 2 texturing or rectangular texturing (most Win32 drivers do) + you shouldn't have any problem with video. Otherwise here are some tips to configure GPAC on your system: + 1- set the "BitmapCopyPixels" option on: some cards perform rather well at direct pixel transfer. If no improvement, set it off. + 2- set the "BitmapCopyPixels" option off and the "EmulatePOW2" option on. This will trick the GL texturing by using only Power Of 2 textures when converting from YUV to RGB. + 3- If this does not improve video playback, you're only chance is through discussion forums & co to gather info about your system, your GL implementation and how to fine-tune it. + +V Misc + + There is a demo 2D authoring tool called V4Studio. No makefiles available yet but should compile without pbs (only needs libgpac + and wxWidgets ). It is not usable to design content but is a funny toy. + + diff --git a/doc/INSTALL.gpe b/doc/INSTALL.gpe new file mode 100644 index 0000000..84169cb --- /dev/null +++ b/doc/INSTALL.gpe @@ -0,0 +1,100 @@ +Installation instructions for GPAC on Familiar+GPE platforms +last modified: December 2008 + +0 Foreword + This file is about installing the GPAC framework on an arm device running Linux familiar (cf http://www.handhelds.org) + + Compilation has only been tested for familiar+GPE platforms ( http://gpe.handhelds.org). + The GPE version enables GPAC to use X11 video output directly, including shared memory extensions. + + The output directory for all plugins and applications is gpac/bin/gcc + + As of 0.2.2, GPAC cannot be compiled without ZLIB. You'd better make sure it is installed on your system (zlib is provided in gpac_extra_libs package) + + To install the arm cross-compilation environement on your linux system, refer to: + * http://www.handhelds.org + * we're currently using the following tool-chain for Familiar+GPE compil http://www.roebling.de/embedded.html, with X11 and GTK+ support, + already compiled. + + Do not forget to update your environment variables according to your toolchain. + +I Extra lib installation + It is recommended to install all extra libs needed by gpac not installed on your system. + +II GPAC compilation + + II.1 SDL Support + GPAC can use SDL for audio/video output. If SDL is not installed on your system, you may indicate configure to build with a local copy: + --sdl-cfg=path/to/local/sdlcfg/ + (make sure to update the local sdl-cfg according to your needs) + + If you can't get SDL and don't have OSS audio nor X11 video support on your system, you won't be able to play any presentation with GPAC, + but you can still use MP4Box. + + II.2 wxWidgets Support + GPAC comes with a GUI player called Osmo4. To compile this player you will need wxWidgets 2.6.0 (2.5.2 should work) installed on your system. + NOTE: Osmo4+wxWidgets is quite slow on familiar+GPE, and is therefore not recommended at the time being. + You can always use GPAC command-line player MP4Client. + + II.3 OpenGL ES support + OpenGL ES is not yet supported on Familiar-GPE. However, GPAC renderer supports OpenGL ES API. Porting the 3D module only requires modifying the X11 output (modules/x11_out) for + OpenGL ES. + + II.4 Building GPAC + go to root of gpac distribution. Note: you may need to "chmod +x" the configure file. + (./configure --help for options) + ./configure --prefix=/usr/local/arm/3.3.2 --cpu=armv4l --enable-fixed-point + Note: this assume the cross-compilation tool-chain is located in /usr/local/arm/3.3.2 + Note: you may also specify any other option supported by configure. It is not recommended to use the floating-point version of GPAC for ARM-based architectures. + make + + II.5 Installing GPAC + copy all files to your device, possibly creating a dedicated directory for modules + edit or create ~/.gpacrc to have at least the following lines: + [General] + ModulesDirectory=AbsolutePathToTheModules + + For more information on GPAC configuration file, cf man GPAC of gpac/doc/configuration.html + +III Running GPAC + + III.1 MP4Client + MP4Client is a command-line interface to GPAC. Note that the player cannot work without video support (so you'd better get SDL) + + You need a GPAC configuration file to run MP4Client, and you will need it each time. + + First launch of MP4Client + go to gpac/bin/gcc if not using the install. + type MP4Client + the prompt will ask for + 1- GPAC plugin dir: enter the path from / to gpac/bin/gcc. This is skipped when using the install version of MP4Client (the plugin path is hardcoded to + the plugins install location on the system) + 2- Font directory: enter the path to a truetype font directory on your system (note that if you don't have compiled with freetype any directory will do) + 3- cache directory: any directory with write access + You now have a valid config file for GPAC, more info on this try "man GPAC" or check gpac/doc/configuration.html. + + The config file is called ".gpacrc" and is located in the user home directory. You may run the client with a different config file by using the "-c" option. + + *If you don't see any output window, check the config file doesn't use raw_out.so as a video renderer (or simply remove raw_out.so). + + III.2 Osmo4 + Osmo4 is the GUI frontend to GPAC. If you have installed Osmo4 on your system, the first launch of the player should ask you to locate a + directory with TrueType fonts and a cache directory for internet downloads if no configuration file is found. + + III.3 MP4Box + MP4Box is a tool to encode, decode and manipulate MPEG-4 systems data. It does not need a configuration file. + Help for MP4Box is available on GPAC web site, with man MP4Box and with 'MP4Box -h' + +IV Configuration + + IV.0 Foreword + All configuration information is described in gpac/doc/configuration.html, or man gpac. + + IV.1 OpenGL + OpenGL is badly known for performing quite poorly as far as high data rate texturing is involved. This is a big issue when displaying a typical movie and you will likely find the GPAC 3D Renderer very slow on your system. If your GPU supports non power of 2 texturing or rectangular texturing (most Win32 drivers do) + you shouldn't have any problem with video. Otherwise here are some tips to configure GPAC on your system: + 1- set the "BitmapCopyPixels" option on: some cards perform rather well at direct pixel transfer. If no improvement, set it off. + 2- set the "BitmapCopyPixels" option off and the "EmulatePOW2" option on. This will trick the GL texturing by using only Power Of 2 textures when converting from YUV to RGB. + 3- If this does not improve video playback, you're only chance is through discussion forums & co to gather info about your system, your GL implementation and how to fine-tune it. + + diff --git a/doc/INSTALL.symbian b/doc/INSTALL.symbian new file mode 100644 index 0000000..3918cd5 --- /dev/null +++ b/doc/INSTALL.symbian @@ -0,0 +1,84 @@ +Installation instructions for GPAC 0.4.5 on Symbian 9.1 (S60 3rd Edition) platform +last modified: December 2008 + +0 Foreword + ! GPAC versions later than 0.4.5 are no longer supported on Symbian ! + + Compilation has only been tested with GCCE & Nokia S60 SDK + In order to fully compile, you must get: + - the complete S60 3rd edition SDK (maintainance release) + - the MMF SDK update + + IMPORTANT NOTE: + You must install the SDK and the code you will compile with it (be it GPAC or anything else) + !! ON THE SAME LOGICAL DRIVE !! + If you do not do so, compilation will simply fail due to some misbehavior of the SDK's environment variables. + + + What is currently supported on symbian: + * all GPAC core, with audio and video output + * MP4 demux, AAC demux, MP3 demux, AMR demux + * native audio media codec from the phone through MMF: AAC and AMR + * MPEG-4 ASP video decoding through xvid + * JPEG and PNG decoding through libjpeg and libpng + * MP3 decoding through MAD + * TrueType fonts through FreeType + * Scripting with JS32 (not fully tested yet) + * FFMPEG (not really stable, random crashes) + + What is currently NOT supported on symbian: + * networking + + TIP: + Global compiler options are located in SDKRoot\Epoc32\tools\compilation_config\ - you may edit the default C++ rules to remove some + warnings during C compil. + + Side notes: + several SDKs may coexist on the drive. + * To see the list of SDKs, at DOS prompt, c:\devices + * To change the default SDK, at DOS prompt, c:\devices -setdefault @sdk_name + you may need to exit prompt and start a new one in order to refresh environment variables. + GPAC should compile on EKA2 (Symbian OS v8.0b, v8.1b). + GPAC CANNOT COMPILE ON EKA1 (Symbian OS v6.1, v7.0, v7.0s, v8.0a v8.1a) because EKA1 does not support writable static data in DLLs + +I Extra lib installation + Please follow the instructions in gpac_extra_lib/00_README_FIRST + +II GPAC compilation + + Go to gpac/build/symbian + + II.1 Configuring extra libs + * If you don't have libjs, libpng or libjpeg for symbian, comment indicated lines in libgpac.mmp (change #if 1 into #if 0) + * If you don't have OpenGL ES for symbian, comment indicated lines in libgpac.mmp (change #if 1 into #if 0) + * If you don't have freetype for symbian, comment ft_font.mmp in file bld.inf + * If you don't have ffmpeg for symbian, comment ffmpeg_in.mmp in file bld.inf + * If you don't have libmad for symbian, comment indicated lines in mp3_in.mmp + * If you don't have libopenjpeg (JPEG 2000) for symbian, comment indicated lines in img_in.mmp (change #if 1 into #if 0) + + II.2 Compiling GPAC + cd gpac/build/symbian + bldmake bldfiles + * for GCCE + abld build gcce urel + * for thumb + abld build thumb urel + cd sis + set EPOCROOT=\path\to\epoc\root\ + * for GCCE + makesis -d%EPOCROOT% osmo4_gcce.pkg + signsis osmo4_gcce.SIS osmo4_gcce.SIS gpac.cer gpac.key password + * for THUMB + makesis -d%EPOCROOT% osmo4_thumb.pkg + + Note: If you need to sign the SIS with your own certificate, you may generate one with openssl: + openssl req -new -x509 -nodes -sha1 -days 3650 -key gpac.key > gpac.cer + +You will get a .SIS package that installs properly on a symbian device. +NOTES: +* The app and plugins are all installed in \sys\bin on the device. DO NOT change this path, since it won't work otherwise (due to symbian 9.1 caged data stuff) +* If you create/succeed to compile a new plugin for GPAC, you must: + - edit build/symbian/sis/osmo4_gcce.pkg to add your plugin in the installer + - edit build/symbian/sis/GPAC.cfg to instruct the player of this new plugin (enumeration of DLLs on Symbian 9.1 is just not possible without a good amount of $$) + + diff --git a/doc/INSTALL.w32 b/doc/INSTALL.w32 new file mode 100644 index 0000000..a338b23 --- /dev/null +++ b/doc/INSTALL.w32 @@ -0,0 +1,217 @@ +Installation instructions for GPAC on windows platform +last modified: May 2012 + +0 Foreword + For any question on the installation procedure, please refer to http://gpac.sourceforge.net/home_download.php + + The output directory for all plugins and applications is + gpac/bin/win32/debug in debug mode + gpac/bin/win32/release in release mode + + As of 0.2.2, GPAC cannot be compiled without ZLIB. You'd better make sure it is installed locally or on your system (zlib is provided in gpac_extra_libs package) + +I Extra lib installation + + It is recommended to download and compile all extra libs needed by gpac on windows. Please read carefull the ReadMe file included in the gpac_extra_libs package + + +II GPAC compilation + + open the GPAC workspace: + gpac/build/msvc6/GPAC.dsw with MSVC6 + gpac/build/msvc8/gpac.sln with VS2005 + gpac/build/msvc9/gpac.sln with VS2008 + + NEVER ATTEMPT TO LOAD A PROJECT OUTSIDE THIS WORKSPACE, AS DEPENDENCY RULES WILL BE BROKEN + + II.1 Recompiling GPAC + libgpac is the core library of the GPAC framework used by all GPAC applications. It is available as a static library and as a dynamic one + Set the "libgpac_dll" project as the active one + If you have not installed the SpiderMonkey (JavaScript, libjs), JPEG or PNG libraries, remove the indicated macros in the file gpac/include/gpac/internal/config_static.h + recompile (libgpac_dll compilation will fail if zlib is not found) + + Note: If you wish to build the fixed-point version of GPAC (not recommended), you will have to modify by hand the file gpac/include/gpac/maths.h + and replace the line + #define GPAC_NO_FIXED_POINT + by the line + #define GPAC_FIXED_POINT + + !!Do not attempts to enable fixed-point compilation in any other way!! + + II.2 Recompiling MP4Box + MP4Box is GPAC command-line tool for content authoring. + Set the "MP4Box" project as the active one + Recompile + + II.3 Plugins check + Before compiling other applications in GPAC you must make sure the projects are configured with the right libraries + + * aac_in + If you have not installed faad2 library, remove the GPAC_HAS_FAAD preprocessor variable from the aac_in project settings. + Note that if no aac decoder is installed for gpac you may as well remove the "aac_in" project from the workspace (DEL). + + * ac3_in + If you have not installed liba52 library, remove the GPAC_HAS_LIBA52 preprocessor variable from the ac3_in project settings. + Note that if no ac3 decoder is installed for gpac you may as well remove the "ac3_in" project from the workspace (DEL). + + * mp3_in + If you have not installed mad library, remove the GPAC_HAS_MAD preprocessor variable from the mp3_in project settings. + Note that if no mp3 decoder is installed for gpac you may as well remove the "mp3_in" project from the workspace (DEL). + + * xvid_dec + if you have not installed xvid library, remove the "xvid_dec" project from the workspace (DEL). + + * img_in: + If you have not installed libopenjpeg, remove the GPAC_HAS_JP2 preprocessor variable from the img_in project settings + and the relevant library from the link settings + If you have not installed any of the above libraries, you may remove the "img_in" project from the workspace (DEL). + + * amr_float_dec + This plugin handles speech coded data using AMR Narrow Band and Wide Band formats. It uses two decoders from the 3GPP consortium available at: + AMR Narrowband decoder: http://www.3gpp.org/ftp/Specs/archive/26_series/26.104/26104-700.zip + AMR Wideband decoder: http://www.3gpp.org/ftp/Specs/archive/26_series/26.204/26204-710.zip + + (The same versions are included in gpac_extra_libs/AMR_NB_FT and gpac_extra_libs/AMR_WB_FT ) + + To compile this plugin, copy the source code to modules/amr_float_dec/amr_nb_ft and modules/amr_float_dec/amr_wb_ft respectively, WITHOUT OVERWRITING typedefs.h files. + You may as well compile with only one of these libraries installed: + If you have not installed AMR NB, remove the GPAC_HAS_AMR_FT preprocessor variable from the amr_float_dec project settings + If you have not installed AMR WB, remove the GPAC_HAS_AMR_FT_WB preprocessor variable from the amr_float_dec project settings + Otherwise, remove the "amr_float_dec" project from the workspace (DEL). + + * amr_dec + This plugin handles speech coded data using AMR Narrow Band format with a fixed-point decoder (suited for embedded platforms). + It uses the decoder of the 3GPP consortium (TS26.073) available from http://www.3gpp.org/ftp/Specs/archive/26_series/26.073/26073-700.zip. + It is the same version included in gpac_extra_libs/AMR_NB with a slight header modifcation. + To compile this plugin, copy the source code to modules/amr_dec/amr_nb WITHOUT OVERWRITING typedefs.h file. + Otherwise, remove the "amr_dec" project from the workspace (DEL). Note you usually won't need this plugin, the float version of the decoders being much faster. + + * ffmpeg_in + To install ffmpeg libraries, cf gpac_extra_libs/ReadMe + if you have not installed ffmpeg libraries (avcodec.lib/dll, avformat.lib/dll, avutil.lib/dll), remove the "ffmpeg_in" project from the workspace (DEL). + + * ft_font + if you have not installed freetype, simply remove the "ft_font" project from the workspace (DEL). + + * gdip_rend + To install GDIPLus, either get Microsft PlatformSDK (http://www.microsoft.com/msdownload/platformsdk/sdkupdate/) or read gpac_extra_libs/GDIPlus/install.txt + if you have not installed GDIPlus or WindowsSDK, remove the "gdip_rend" project from the workspace (DEL). + + * ogg + if you have not installed libogg library, remove the "ogg" project from the workspace (DEL). + if you have not installed libvorbis library, remove the GPAC_HAS_VORBIS preprocessor variable from the ogg project settings + if you have not installed libtheora library, remove the GPAC_HAS_THEORA preprocessor variable from the ogg project settings + Note that if you have only installed libogg you can also remove the "ogg" project from the workspace, it won't be any usefull. + + * sdl_out: + GPAC can use SDL library for audio (all clients) and video (MP4Client and wxOsmo4) output. + You will need to get SDL 1.2 for windows. Get it at http://www.libsdl.org/download-1.2.php. You need the DEVELOPMENT LIBRARY SDL-devel-1.2.7-VC6.zip + Unpack and setup your path or VisualC++ for SDL include and lib directories (you may need to restart VisualC++) + You will need to modify your VC settings to look for libxml headers and library directories. + If you don't want to install libSDL or don't plan to use MP4Client or wxOsmo4, simply remove the "sdl_out" project from the workspace (DEL). + NOTE: SDL is not needed at all on windows, you will still have audio and video support without SDL. The SDL plugin is much slower than the directX plugin + when dealing with video since it uses software YUV to RGB conversion. + + NOTE: if you have not installed GDIPlus nor freetype, you won't have text support at all in GPAC. + + + II.4 Recompiling Osmo4 + Osmo4 is the GUI MPEG-4 player of GPAC for the windows platform. + Set Osmo4 as the active project + recompile (enabled plugins will be recompiled in the process) + + II.5 Recompiling MP4Client + MP4Client is the command MPEG-4 player of GPAC. + Set MP4Client as the active project + recompile (enabled plugins will be recompiled in the process) + + II.6 Recompiling Osmo4/wxWidgets + Osmo4 / wxWidgets is the cross-platform GUI MPEG-4 player of GPAC. You must have wxWidgets 2.6.0 installed and configured on your system (this may be tricky. Please + make sure you can recompile some sample wxWidgets applications from wxWidgets distribution first). + Set wxOsmo4 as the active project + recompile (some plugins may be recompiled in the process). You may need to change the linker settings, depending on your wxWidgets version and config + + II.7 Recompiling Osmozilla + Osmozilla is GPAC plugin for Mozilla-based browsers, enabling embedding all GPAC supported contents in a web page. Recompile it only if you think it may + be helpful. + * Get the gecko sdk (http://ftp.mozilla.org/pub/mozilla.org/mozilla/releases/mozilla1.7.13/gecko-sdk-i586-pc-msvc-1.7.13.zip or in the gpac_extra_libs package) + * Extract it to gpac/extra_lib/include/gecko-sdk + * Set Osmozilla as the active project and recompile + + II.7 Recompiling GPAX + GPAX is GPAC ActiveX control, only usable as an Internet Explorer plugin for now, enabling to embed all GPAC supported contents in a web page. Recompile it only if you think it may + be helpful (Set as the active project and recompile) + +III Launching the applications + + If you have compiled libgpac with SpiderMonkey (JavaScript) enabled, copy the JS32.dll file in the output directory. + + Some applications need to locate the GPAC configuration file called GPAC.cfg. This file is automatically generated by Osmo4 in its directory. It is recommended +to first launch Osmo4 to get a working config file. + For more information regarding the config file, cf gpac/doc/configuration.html + + You can launch Osmo4 as is, the application should start and be operational right away. + + You can use MP4Box as is. + + MP4Client needs GPAC configuration file to run. It will by default search for the file in the current directory, and some hardcoded directories that will likely not work. + If the config file is not found, a new one is created in the current directory. You can pass a given config file as a parameter (MP4Client -c config_path). + You can also modify the hardcoded path in MP4Client (gpac/Applications/MP4Client/main.c) to point to gpac output directory and recompile. + + + Osmozilla cannot be launched without a mozilla-based web browser. You should not try to install it in any other way than with the GPAC installer + (cf below). Once installed, you may try any test in an html page viewed with your browser, for example: + + + + To make sure your browser has loaded the osmozilla plugin and to check the mime types supported, try typing "about:plugins" in your browser address bar. + + GPAX cannot be launched without Internet Explorer. You should not try to install it in any other way than with the GPAC installer + (cf below). Once installed, you may try any test in an html page viewed with your browser, for instance: + + + + + +IV Configuration + + IV.0 Foreword + All configuration information is described in gpac/doc/configuration.html, or man gpac. + + IV.1 OpenGL + OpenGL is badly known for performing quite poorly as far as high data rate texturing is involved. This is a big issue when displaying a typical movie and you + will likely find the GPAC 3D Renderer very slow on your system. If your GPU supports non power of 2 texturing or rectangular texturing (most Win32 drivers do) + you shouldn't have any problem with video. Otherwise here are some tips to configure GPAC on your system: + 1- set the "BitmapCopyPixels" option on: some cards perform rather well at direct pixel transfer. If no improvement, set it off. + 2- set the "BitmapCopyPixels" option off and the "EmulatePOW2" option on. This will trick the GL texturing by using only Power Of 2 textures when converting + from YUV to RGB. + 3- If this does not improve video playback, you're only chance is through discussion forums & co to gather info about your system, your GL implementation + and how to fine-tune it. + +V Misc + + V.1 Scene Generators + In gpac/applications/generators you will find the code generators for MPEG-4, X3D and SVG scene graphs used in gpac. + If you want to modify the set of nodes understood by GPAC in encoding/decoding/rendering, you will need those. + The Scene generators can be recompiled without dependencies to extra libraries nor libgpac library. + To recompile them, open the related project files (.dsp) and recompile. + To use them, cf gpac/doc/SceneGenerators + + VI.2 V4Studio + V4Studio is a very simple authoring tool for 2D content. It is not usable but may interest developers. + For Installation instructions cf gpac/Applications/V4Studio/install + + VI.3 GPAC Installer + The GPAC installer uses the NSIS installing system. The installation script is gpac/bin/w32_rel/install/GPAC_Install.nsi + - Before building the installer + * get NullSoft installer (nsis.sourceforge.net), at least version 2.0 + * make sure the js32.dll is copied in the gpac/bin/w32_rel dir if you have compiled GPAC with SpiderMonkey support, otherwise comment + out "..\js32.dll" line from the install script + * copy gdiplus.dll to gpac/bin/w32_rel/install + * make sure avcodec.dll and avformat.dll are copied in gpac/bin/w32_rel if you have built ffmpeg plugin + * make sure iconv.dll, libxml2.dll, zlib1.dll in gpac/bin/w32_rel if you have compiled libxml2 + + - Building GPAC installer + The installer includes Osmo4, MP4Box, Osmozilla and all modules except SDL_out and raw_out. To install, right click on "GPAC_Install.nsi" and compile + For other configurations, modify the script "GPAC_Install.nsi" to comment out unwanted features + diff --git a/doc/INSTALL.wCE b/doc/INSTALL.wCE new file mode 100644 index 0000000..e308319 --- /dev/null +++ b/doc/INSTALL.wCE @@ -0,0 +1,134 @@ +Installation instructions for GPAC on windows CE platform +last modified: Mai 2012 + +0 Foreword + + ** GPAC IS NO LONGER MAINTAINED ON PocketPC 2002/eVC3 PLATFORMS ** + + Compilation has only been tested with evc4 and ARM platforms + + GPAC should be stable on most devices running PocketPC/SmartPhone 2003. It has know bugs with higher versions + of the Windows Mobile OS, but should still be stable. + + The output directory for all plugins and applications for Windows PocketPC 2003 is + gpac/bin/Smartphone 2003/Debug in debug mode + gpac/bin/Smartphone 2003/Release in release mode + + As of 0.2.2, GPAC cannot be compiled without ZLIB. You'd better make sure it is installed locally or on your system (zlib is provided in gpac_extra_libs package) + +I Extra lib installation + It is recommended to download and compile all extra libs needed by gpac on winCE. + In case you don't do so, you will need to to modify project settings. + + +II GPAC compilation + open /build/msvc8/gpac.sln (GPAC workspace) with MSVC 2005 + open /build/msvc9/gpac.sln (GPAC workspace) with MSVC 2008 + + NEVER ATTEMPT TO LOAD A PROJECT OUTSIDE THIS WORKSPACE + + II.1 Setting up libgpac + libgpac is the core library of the GPAC framework used by all GPAC applications + + If you have not installed the SpiderMonkey (JavaScript, libjs), JPEG or PNG libraries, remove the indicated macros in the file gpac/include/gpac/internal/config_static.h + + If you are compiling for PocketPC 2003 OS, and wish to use the Intel GPP library, uncomment the desired macro in + the file gpac/include/gpac/internal/config_static.h + + 3D Rendering + GPAC can use OpenGL ES for 3D rendering on embedded devices, but you will need development files of OpenGL ES. + GPAC has been tested with 2 implementations of OpenGL ES: + * HybridGraphics one (cf http://www.hybrid.fi/), by far the most efficient one tested, available for evc4/PockePC 2003 only + * Vincent3D (aka ogl-es, cf http://ogl-es.sourceforge.net/), slower but with good visual results + + To setup OpenGL ES, get one of these libraries, configure the IDE to locate the include and lib files (or copy them in gpac/extra_lib/ which is setup by default) + The GL ES lib shall be named "libGLES_CM.lib" or "libGLES_CL.lib" for the OpenGL-ES Light profile, and the GL ES include files shall be located in a "GLES" directory, the include path pointing to its parent directory. + + NOTE 1: The Klimt library (cf http://studierstube.org/klimt/), which is not 100% OpenGL_ES compliant, may be used but needs some code rewrite here and there, + mainly in gapi video output. + + NOTE 2: If you do not plan to support 3D rendering, uncomment the related macro in the file gpac/include/gpac/internal/config_static.h + + + II.2 Checking Plugins + + Before compiling GPAC plugins, you must make sure the projects are configured with the right libraries + * aac_in + If you have not installed faad2 library, remove the GPAC_HAS_FAAD preprocessor variable from the aac_in project settings. + Note that if no aac decoder is installed for gpac you may as well remove the "aac_in" project from the workspace (DEL). + + * ac3_in + If you have not installed liba52 library, remove the GPAC_HAS_LIBA52 preprocessor variable from the ac3_in project settings. + Note that if no ac3 decoder is installed for gpac you may as well remove the "ac3_in" project from the workspace (DEL). + + * mp3_in + If you have not installed mad library, remove the GPAC_HAS_MAD preprocessor variable from the mp3_in project settings. + Note that if no mp3 decoder is installed for gpac you may as well remove the "mp3_in" project from the workspace (DEL). + + * amr_nb + This plugin handles speech coded data using AMR Narrow Band format. It uses the decoder of the 3GPP consortium (TS26.073) available + from http://www.3gpp.org/ftp/Specs/archive/26_series/26.073/26073-700.zip. + It is the same version included in gpac_extra_libs/AMR_NB with a slight header modifcation. + To compile this plugin, copy the source code to modules/amr_dec/amr_nb WITHOUT OVERWRITING typedefs.h file. + Otherwise, remove the "amr_dec" project from the workspace (DEL). + + * img_in: + If you have not installed libopenjpeg, remove the GPAC_HAS_JP2 preprocessor variable from the img_in project settings + and the relevant library from the link settings + If none of the above lib is installed, you can simply remove the img_in project from the workspace (DEL). + + * ft_font + if you have not installed freetype, remove the project dependecies to freetype in project Osmo4 and MP4Client + NOTE: if you have not installed freetype, you won't have text support at all in GPAC. + + * ogg + if you have not installed libogg library, remove the "ogg" project from the workspace (DEL). + if you have not installed libvorbis library, remove the GPAC_HAS_VORBIS preprocessor variable from the ogg project settings + if you have not installed libtheora library, remove the GPAC_HAS_THEORA preprocessor variable from the ogg project settings + Note that if you have only installed libogg you can also remove the "ogg" project from the workspace, it won't be any usefull. + + * gapi: + you must make sure you have installed the GAPI SDK for windows (also known as GX) before compiling - cf gpac_extra_libs/ReadMe + + II.3 Recompiling + select the target platform (PocketPC or Smartphone) + Rebuild all (Build->Batch Build->Rebuild All) + + Note: + Osmo4 build will fail for smartphone devices, the GPAC GUI available on this platform is Osmophone + + II.4 Launching Osmo4 or Osmophone + Osmo4/Osmophone will automatically create a config file in the Osmo4/Osmophone executable directory if needed. You must copy all plugins to this + directory (recommended), or edit by hand the config file "ModulesDirectory" key to point to the modules directory, otherwise Osmo4/Osmophone will not + launch. You can then launch Osmo4/Osmophone (cf Misc section below) + +III GPAC Installer for WinCE + + The GPAC installer uses MS installer and EZSetup to get an Osmo4/Osmophone installer on PocketPC 2003 Systems + Install scripts are located in gpac/bin/arm_ppc02_rel/install and gpac/bin/arm_ppc03_rel/install + THIS INSTALLER IS ONLY INTENDED FOR STRONGARM BASED DEVICES + + * compile GPAC for PocketPC 2003 + * make sure the js.dll is copied in the release build directory if you have compiled GPAC with SpiderMonkey support, otherwise comment lines "js.dll" in gpac.inf + * make sure the libGLES_CM.dll (or libGLES_CL.dll ) is copied in the release build directory if you have compiled with OpenGL ES support, otherwise comment lines "libGLES_CM.dll" and "gm_render3d.dll" in gpac.inf + * make sure the libxml2.dll is copied in the release build directory if you have compiled the svg loader, otherwise comment lines "libxml2.dll" in gpac.inf + * remove any lines in gpac.inf that refer to plugins you have not built. + * if you have built the smartphone version, change AppName and ExeName accordingly in gpac.inf + * get MS PocketPC Cabwizard (search for Cabwiz.exe in your ActiveSync distribution) + * copy cabwiz.exe, cabwiz.ddf and MAKECAB.exe in the install directory + * if needed copy gx.dll in the install directory (download from microsoft, or use gpac extra libs version) + * get Ezsetup from http://www.eskimo.com/~scottlu/win/, and copy it in this directory + * run do.bat file + +IV Misc + + IV.1 Note on Video + As of 0.2.3, the OpenDivx plugin is no longer included in GPAC. A new, modified version of XviD 1.0 for ARM is included (cf gpac/modules/xvid_dec/xvid_wce/ReadMe.txt) + + IV.2 Note on Network + Ipaq devices under WindowsCE below Windows CE .NET 4.1 (and maybe other devices) have a small default UDP buffer size, and this buffer size cannot + be changed through WinSock (software) calls. To increase it, you must manually edit the registry and set (add a DWORD key if not present): + HKEY_LOCAL_MACHINE\Comm\Afd\DgramBuffer 16 + 16 is the maximum value possible, DON'T TRY TO SPECIFY MORE. + The device MUST be reseted (soft reset, cf your manual) for the parameter to be taken into account. + diff --git a/doc/ISO 639-2 codes.txt b/doc/ISO 639-2 codes.txt new file mode 100644 index 0000000..7296581 --- /dev/null +++ b/doc/ISO 639-2 codes.txt @@ -0,0 +1,487 @@ +Codes used in GPAC are according to ISO/IEC 639-2/T + + "Abkhazian","abk","ab", + "Achinese","ace","", + "Acoli","ach","", + "Adangme","ada","", + "Adyghe; Adygei","ady","", + "Afar","aar","aa", + "Afrihili","afh","", + "Afrikaans","afr","af", + "Afro-Asiatic languages","afa","", + "Ainu","ain","", + "Akan","aka","ak", + "Akkadian","akk","", + "Albanian","sqi","sq", + "Aleut","ale","", + "Algonquian languages","alg","", + "Altaic languages","tut","", + "Amharic","amh","am", + "Angika","anp","", + "Apache languages","apa","", + "Arabic","ara","ar", + "Aragonese","arg","an", + "Arapaho","arp","", + "Arawak","arw","", + "Armenian","hye","hy", + "Aromanian; Arumanian; Macedo-Romanian","rup","", + "Artificial languages","art","", + "Assamese","asm","as", + "Asturian; Bable; Leonese; Asturleonese","ast","", + "Athapascan languages","ath","", + "Australian languages","aus","", + "Austronesian languages","map","", + "Avaric","ava","av", + "Avestan","ave","ae", + "Awadhi","awa","", + "Aymara","aym","ay", + "Azerbaijani","aze","az", + "Balinese","ban","", + "Baltic languages","bat","", + "Baluchi","bal","", + "Bambara","bam","bm", + "Bamileke languages","bai","", + "Banda languages","bad","", + "Bantu languages","bnt","", + "Basa","bas","", + "Bashkir","bak","ba", + "Basque","eus","eu", + "Batak languages","btk","", + "Beja; Bedawiyet","bej","", + "Belarusian","bel","be", + "Bemba","bem","", + "Bengali","ben","bn", + "Berber languages","ber","", + "Bhojpuri","bho","", + "Bihari languages","bih","bh", + "Bikol","bik","", + "Bini; Edo","bin","", + "Bislama","bis","bi", + "Blin; Bilin","byn","", + "Blissymbols; Blissymbolics; Bliss","zbl","", + "BokmÃ¥l, Norwegian; Norwegian BokmÃ¥l","nob","nb", + "Bosnian","bos","bs", + "Braj","bra","", + "Breton","bre","br", + "Buginese","bug","", + "Bulgarian","bul","bg", + "Buriat","bua","", + "Burmese","mya","my", + "Caddo","cad","", + "Catalan; Valencian","cat","ca", + "Caucasian languages","cau","", + "Cebuano","ceb","", + "Celtic languages","cel","", + "Central American Indian languages","cai","", + "Central Khmer","khm","km", + "Chagatai","chg","", + "Chamic languages","cmc","", + "Chamorro","cha","ch", + "Chechen","che","ce", + "Cherokee","chr","", + "Cheyenne","chy","", + "Chibcha","chb","", + "Chichewa; Chewa; Nyanja","nya","ny", + "Chinese","zho","zh", + "Chinook jargon","chn","", + "Chipewyan; Dene Suline","chp","", + "Choctaw","cho","", + "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic","chu","cu", + "Chuukese","chk","", + "Chuvash","chv","cv", + "Classical Newari; Old Newari; Classical Nepal Bhasa","nwc","", + "Classical Syriac","syc","", + "Coptic","cop","", + "Cornish","cor","kw", + "Corsican","cos","co", + "Cree","cre","cr", + "Creek","mus","", + "Creoles and pidgins","crp","", + "Creoles and pidgins, English based","cpe","", + "Creoles and pidgins, French-based","cpf","", + "Creoles and pidgins, Portuguese-based","cpp","", + "Crimean Tatar; Crimean Turkish","crh","", + "Croatian","hrv","hr", + "Cushitic languages","cus","", + "Czech","ces","cs", + "Dakota","dak","", + "Danish","dan","da", + "Dargwa","dar","", + "Delaware","del","", + "Dinka","din","", + "Divehi; Dhivehi; Maldivian","div","dv", + "Dogri","doi","", + "Dogrib","dgr","", + "Dravidian languages","dra","", + "Duala","dua","", + "Dutch, Middle (ca.1050-1350)","dum","", + "Dutch; Flemish","nld","nl", + "Dyula","dyu","", + "Dzongkha","dzo","dz", + "Eastern Frisian","frs","", + "Efik","efi","", + "Egyptian (Ancient)","egy","", + "Ekajuk","eka","", + "Elamite","elx","", + "English","eng","en", + "English, Middle (1100-1500)","enm","", + "English, Old (ca.450-1100)","ang","", + "Erzya","myv","", + "Esperanto","epo","eo", + "Estonian","est","et", + "Ewe","ewe","ee", + "Ewondo","ewo","", + "Fang","fan","", + "Fanti","fat","", + "Faroese","fao","fo", + "Fijian","fij","fj", + "Filipino; Pilipino","fil","", + "Finnish","fin","fi", + "Finno-Ugrian languages","fiu","", + "Fon","fon","", + "French","fra","fr", + "French, Middle (ca.1400-1600)","frm","", + "French, Old (842-ca.1400)","fro","", + "Friulian","fur","", + "Fulah","ful","ff", + "Ga","gaa","", + "Gaelic; Scottish Gaelic","gla","gd", + "Galibi Carib","car","", + "Galician","glg","gl", + "Ganda","lug","lg", + "Gayo","gay","", + "Gbaya","gba","", + "Geez","gez","", + "Georgian","kat","ka", + "German","deu","de", + "German, Middle High (ca.1050-1500)","gmh","", + "German, Old High (ca.750-1050)","goh","", + "Germanic languages","gem","", + "Gilbertese","gil","", + "Gondi","gon","", + "Gorontalo","gor","", + "Gothic","got","", + "Grebo","grb","", + "Greek, Ancient (to 1453)","grc","", + "Greek, Modern (1453-)","ell","el", + "Guarani","grn","gn", + "Gujarati","guj","gu", + "Gwich'in","gwi","", + "Haida","hai","", + "Haitian; Haitian Creole","hat","ht", + "Hausa","hau","ha", + "Hawaiian","haw","", + "Hebrew","heb","he", + "Herero","her","hz", + "Hiligaynon","hil","", + "Himachali languages; Western Pahari languages","him","", + "Hindi","hin","hi", + "Hiri Motu","hmo","ho", + "Hittite","hit","", + "Hmong; Mong","hmn","", + "Hungarian","hun","hu", + "Hupa","hup","", + "Iban","iba","", + "Icelandic","isl","is", + "Ido","ido","io", + "Igbo","ibo","ig", + "Ijo languages","ijo","", + "Iloko","ilo","", + "Inari Sami","smn","", + "Indic languages","inc","", + "Indo-European languages","ine","", + "Indonesian","ind","id", + "Ingush","inh","", + "Interlingua (International Auxiliary Language Association)","ina","ia", + "Interlingue; Occidental","ile","ie", + "Inuktitut","iku","iu", + "Inupiaq","ipk","ik", + "Iranian languages","ira","", + "Irish","gle","ga", + "Irish, Middle (900-1200)","mga","", + "Irish, Old (to 900)","sga","", + "Iroquoian languages","iro","", + "Italian","ita","it", + "Japanese","jpn","ja", + "Javanese","jav","jv", + "Judeo-Arabic","jrb","", + "Judeo-Persian","jpr","", + "Kabardian","kbd","", + "Kabyle","kab","", + "Kachin; Jingpho","kac","", + "Kalaallisut; Greenlandic","kal","kl", + "Kalmyk; Oirat","xal","", + "Kamba","kam","", + "Kannada","kan","kn", + "Kanuri","kau","kr", + "Kara-Kalpak","kaa","", + "Karachay-Balkar","krc","", + "Karelian","krl","", + "Karen languages","kar","", + "Kashmiri","kas","ks", + "Kashubian","csb","", + "Kawi","kaw","", + "Kazakh","kaz","kk", + "Khasi","kha","", + "Khoisan languages","khi","", + "Khotanese; Sakan","kho","", + "Kikuyu; Gikuyu","kik","ki", + "Kimbundu","kmb","", + "Kinyarwanda","kin","rw", + "Kirghiz; Kyrgyz","kir","ky", + "Klingon; tlhIngan-Hol","tlh","", + "Komi","kom","kv", + "Kongo","kon","kg", + "Konkani","kok","", + "Korean","kor","ko", + "Kosraean","kos","", + "Kpelle","kpe","", + "Kru languages","kro","", + "Kuanyama; Kwanyama","kua","kj", + "Kumyk","kum","", + "Kurdish","kur","ku", + "Kurukh","kru","", + "Kutenai","kut","", + "Ladino","lad","", + "Lahnda","lah","", + "Lamba","lam","", + "Land Dayak languages","day","", + "Lao","lao","lo", + "Latin","lat","la", + "Latvian","lav","lv", + "Lezghian","lez","", + "Limburgan; Limburger; Limburgish","lim","li", + "Lingala","lin","ln", + "Lithuanian","lit","lt", + "Lojban","jbo","", + "Low German; Low Saxon; German, Low; Saxon, Low","nds","", + "Lower Sorbian","dsb","", + "Lozi","loz","", + "Luba-Katanga","lub","lu", + "Luba-Lulua","lua","", + "Luiseno","lui","", + "Lule Sami","smj","", + "Lunda","lun","", + "Luo (Kenya and Tanzania)","luo","", + "Lushai","lus","", + "Luxembourgish; Letzeburgesch","ltz","lb", + "Macedonian","mkd","mk", + "Madurese","mad","", + "Magahi","mag","", + "Maithili","mai","", + "Makasar","mak","", + "Malagasy","mlg","mg", + "Malay","msa","ms", + "Malayalam","mal","ml", + "Maltese","mlt","mt", + "Manchu","mnc","", + "Mandar","mdr","", + "Mandingo","man","", + "Manipuri","mni","", + "Manobo languages","mno","", + "Manx","glv","gv", + "Maori","mri","mi", + "Mapudungun; Mapuche","arn","", + "Marathi","mar","mr", + "Mari","chm","", + "Marshallese","mah","mh", + "Marwari","mwr","", + "Masai","mas","", + "Mayan languages","myn","", + "Mende","men","", + "Mi'kmaq; Micmac","mic","", + "Minangkabau","min","", + "Mirandese","mwl","", + "Mohawk","moh","", + "Moksha","mdf","", + "Mon-Khmer languages","mkh","", + "Mongo","lol","", + "Mongolian","mon","mn", + "Mossi","mos","", + "Multiple languages","mul","", + "Munda languages","mun","", + "N'Ko","nqo","", + "Nahuatl languages","nah","", + "Nauru","nau","na", + "Navajo; Navaho","nav","nv", + "Ndebele, North; North Ndebele","nde","nd", + "Ndebele, South; South Ndebele","nbl","nr", + "Ndonga","ndo","ng", + "Neapolitan","nap","", + "Nepal Bhasa; Newari","new","", + "Nepali","nep","ne", + "Nias","nia","", + "Niger-Kordofanian languages","nic","", + "Nilo-Saharan languages","ssa","", + "Niuean","niu","", + "No linguistic content; Not applicable","zxx","", + "Nogai","nog","", + "Norse, Old","non","", + "North American Indian languages","nai","", + "Northern Frisian","frr","", + "Northern Sami","sme","se", + "Norwegian","nor","no", + "Norwegian Nynorsk; Nynorsk, Norwegian","nno","nn", + "Nubian languages","nub","", + "Nyamwezi","nym","", + "Nyankole","nyn","", + "Nyoro","nyo","", + "Nzima","nzi","", + "Occitan (post 1500)","oci","oc", + "Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)","arc","", + "Ojibwa","oji","oj", + "Oriya","ori","or", + "Oromo","orm","om", + "Osage","osa","", + "Ossetian; Ossetic","oss","os", + "Otomian languages","oto","", + "Pahlavi","pal","", + "Palauan","pau","", + "Pali","pli","pi", + "Pampanga; Kapampangan","pam","", + "Pangasinan","pag","", + "Panjabi; Punjabi","pan","pa", + "Papiamento","pap","", + "Papuan languages","paa","", + "Pedi; Sepedi; Northern Sotho","nso","", + "Persian","fas","fa", + "Persian, Old (ca.600-400 B.C.)","peo","", + "Philippine languages","phi","", + "Phoenician","phn","", + "Pohnpeian","pon","", + "Polish","pol","pl", + "Portuguese","por","pt", + "Prakrit languages","pra","", + "Provençal, Old (to 1500);Occitan, Old (to 1500)","pro","", + "Pushto; Pashto","pus","ps", + "Quechua","que","qu", + "Rajasthani","raj","", + "Rapanui","rap","", + "Rarotongan; Cook Islands Maori","rar","", + "Reserved for local use","qaa-qtz","", + "Romance languages","roa","", + "Romanian; Moldavian; Moldovan","ron","ro", + "Romansh","roh","rm", + "Romany","rom","", + "Rundi","run","rn", + "Russian","rus","ru", + "Salishan languages","sal","", + "Samaritan Aramaic","sam","", + "Sami languages","smi","", + "Samoan","smo","sm", + "Sandawe","sad","", + "Sango","sag","sg", + "Sanskrit","san","sa", + "Santali","sat","", + "Sardinian","srd","sc", + "Sasak","sas","", + "Scots","sco","", + "Selkup","sel","", + "Semitic languages","sem","", + "Serbian","srp","sr", + "Serer","srr","", + "Shan","shn","", + "Shona","sna","sn", + "Sichuan Yi; Nuosu","iii","ii", + "Sicilian","scn","", + "Sidamo","sid","", + "Sign Languages","sgn","", + "Siksika","bla","", + "Sindhi","snd","sd", + "Sinhala; Sinhalese","sin","si", + "Sino-Tibetan languages","sit","", + "Siouan languages","sio","", + "Skolt Sami","sms","", + "Slave (Athapascan)","den","", + "Slavic languages","sla","", + "Slovak","slk","sk", + "Slovenian","slv","sl", + "Sogdian","sog","", + "Somali","som","so", + "Songhai languages","son","", + "Soninke","snk","", + "Sorbian languages","wen","", + "Sotho, Southern","sot","st", + "South American Indian languages","sai","", + "Southern Altai","alt","", + "Southern Sami","sma","", + "Spanish; Castilian","spa","es", + "Sranan Tongo","srn","", + "Sukuma","suk","", + "Sumerian","sux","", + "Sundanese","sun","su", + "Susu","sus","", + "Swahili","swa","sw", + "Swati","ssw","ss", + "Swedish","swe","sv", + "Swiss German; Alemannic; Alsatian","gsw","", + "Syriac","syr","", + "Tagalog","tgl","tl", + "Tahitian","tah","ty", + "Tai languages","tai","", + "Tajik","tgk","tg", + "Tamashek","tmh","", + "Tamil","tam","ta", + "Tatar","tat","tt", + "Telugu","tel","te", + "Tereno","ter","", + "Tetum","tet","", + "Thai","tha","th", + "Tibetan","bod","bo", + "Tigre","tig","", + "Tigrinya","tir","ti", + "Timne","tem","", + "Tiv","tiv","", + "Tlingit","tli","", + "Tok Pisin","tpi","", + "Tokelau","tkl","", + "Tonga (Nyasa)","tog","", + "Tonga (Tonga Islands)","ton","to", + "Tsimshian","tsi","", + "Tsonga","tso","ts", + "Tswana","tsn","tn", + "Tumbuka","tum","", + "Tupi languages","tup","", + "Turkish","tur","tr", + "Turkish, Ottoman (1500-1928)","ota","", + "Turkmen","tuk","tk", + "Tuvalu","tvl","", + "Tuvinian","tyv","", + "Twi","twi","tw", + "Udmurt","udm","", + "Ugaritic","uga","", + "Uighur; Uyghur","uig","ug", + "Ukrainian","ukr","uk", + "Umbundu","umb","", + "Uncoded languages","mis","", + "Undetermined","und","", + "Upper Sorbian","hsb","", + "Urdu","urd","ur", + "Uzbek","uzb","uz", + "Vai","vai","", + "Venda","ven","ve", + "Vietnamese","vie","vi", + "Volapük","vol","vo", + "Votic","vot","", + "Wakashan languages","wak","", + "Walloon","wln","wa", + "Waray","war","", + "Washo","was","", + "Welsh","cym","cy", + "Western Frisian","fry","fy", + "Wolaitta; Wolaytta","wal","", + "Wolof","wol","wo", + "Xhosa","xho","xh", + "Yakut","sah","", + "Yao","yao","", + "Yapese","yap","", + "Yiddish","yid","yi", + "Yoruba","yor","yo", + "Yupik languages","ypk","", + "Zande languages","znd","", + "Zapotec","zap","", + "Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki","zza","", + "Zenaga","zen","", + "Zhuang; Chuang","zha","za", + "Zulu","zul","zu", + "Zuni","zun","", diff --git a/doc/SceneGenerators b/doc/SceneGenerators new file mode 100644 index 0000000..5229e70 --- /dev/null +++ b/doc/SceneGenerators @@ -0,0 +1,148 @@ + GPAC Scene Graph generator documentation - v0.4.0 + + Last Modified: July 2005 + + + +0 - Foreword + + + +The sets (MPEG4, X3D and SVG) of nodes handled by the GPAC are genrated through "Scene Generators" applications: + +applications/generators/MPEG4 for MPEG4 along with the official MPEG-4 template files needed to generate nodes and their encoding tables. + +applications/generators/X3D for X3D along with the X3D template file needed to generate nodes. + +applications/generators/SVG for SVG along with the SVG template. + + + +MPEG-4 Template files are numbered by versions of amendments to the MPEG-4 systems standard. + +X3D and SVG templates do not have versionning. + + + +1 - Regenerating the scene graph + + + +First recompile the appropriated scene generator application. You don't need to recompile GPAC to recompile it. + +The generators DIRECTLY overwrites source code files in the GPAC distribution, you MUST NOT try to run it from a different + +location than gpac/applications/generators/* + + + +For MPEG-4 you must provide MPEG4Gen with the set of template files. For example, if you're planning to use only nodes defined in the + +first version of the standard (1998) described in templates1.txt file, just type: + + + +MPEG4Gen templates1.txt + + + +Template files MUST be fed in order, and versions cannot be skipped: you SHALL NOT try to generate version1 and version3 without version2. + +To generate a scene graph handling v1 to v3 of the BIFS system, type: + +MPEG4Gen templates1.txt templates2.txt templates3.txt + + + +For X3D, simply run X3DGen, it will automatically load the "templates_X3D.txt" file + +For SVG, simply run SVGGen completesvgt12rng.xml + + + + + +2 - Customizing the scene graph + + + +As of 0.2.2, all nodes in current gpac version are supported by renderers and cannot be removed. You will therefore have to REMOVE some code in the renderers + +and the scene graph in order to recompile GPAC. You should therefore not try to customize the scene graph unless you know what you're doing. + + + + 2.1 - Customizing the MPEG-4 scene graph + + + +As said above, it is not possible to skip a BIFS version when regenerating the scene graph since this will break binary encoding of the nodes. + +However MPEG4Gen allows you to specify which nodes should be supported or not in the scene graph. This is currently specified + +with a simple text file where unwanted nodes are listed one by line ('#' acting as a line comment). The file is specified by + +the "-p " switch + + + +For example, generating a scene graph for BIFS V1 without support for the BIFS audio nodes will be: + +MPEG4Gen -p skip_audio.txt templates1.txt + + + +and the content of skip_audio.txt file will be + + + +AudioBuffer + +AudioClip + +AudioDelay + +AudioFX + +AudioMix + +AudioSwitch + +AudioSource + + + + 2.2 - Customizing the X3D scene graph + + + +X3DGen uses the same mechanism as MPEG4Gen for node skinpping, eg: X3DGen skipfile + + + + 2.3 - Customizing the SVG scene graph + + + +This is undocumented and probably not supported + + + +3 - Advanced Manupulations + + + + It is possible to develop custom templates. The resulting encoding/decoding will not be compliant with MPEG-4 BIFS but it can + +be interesting to see how a single-version mechanism with only the desired nodes reduces applications and bitstreams sizes + +To write your own templates, you must: + + follow the syntax of regular templates + + make sure the SFWorldNode type is defined and used by all nodes (needed for BIFS updates) + + make sure at least one node will be of type SFTopNode (needed for BIFS Scene Replace command) + + + diff --git a/doc/configuration.html b/doc/configuration.html new file mode 100644 index 0000000..b1c2ec4 --- /dev/null +++ b/doc/configuration.html @@ -0,0 +1,903 @@ + + + + + + GPAC Configuration documentation + + +

+
+GPAC Configuration file documentation
Version 0.5.2-dev
+
+

+ +

+ +
Overview +

+Some applications in the GPAC framework use a configuration file shared among modules and reloadable at run time. Modules may use the configuration file as well (to avoid multiple config files). This doc attempts to provide explanations for the different options. +

+The config file is ordered by sections and keys. +
A section is declared as SectionName. Defined sections are: +
+General +RecentFiles +Systems +Compositor +Audio +Video +Network +FontEngine +Downloader +HTTPProxy +Streaming +MimeTypes +StreamingCache +SAXLoader +XviD +FFMPEG +ISOReader +DVB +DASH +ALSA +Shortcuts +DSMCC +OpenHEVC +DirectFB +DektecVideo + +

+

+A key is declared as keyName=value. The key value is not interpreted and always handled as ASCII text. +

+
    +
  • +On Windows plateforms, this config file is called "GPAC.cfg" and is usually located in C:\\Program Files\\GPAC. Note that Osmo4 will always create a config file in its own directory when none is found. +

    +
  • +
  • +On Windows CE plateform, this config file is called "GPAC.cfg" and is usually located in \\Program Files\\GPAC. Note that Osmo4 / CE will always create a config file in its own directory when none is found. +

    +
  • +
  • +On GNU/Linux plateforms, this config file is called ".gpacrc" and is always located at the root of the user home directory (for ex, /home/jean/.gpacrc). +

    +
  • +
+
+ +

Note on module names: +
Module names as given in the config file are names exported by each interface and not name of the physical library file (.dll, .so, ...). The physical file name can however be used to identify a module - it will then be replaced by the module name. + +

+

+ + +Section "General" Back to top +

+The General section of the config file holds player specific options. +

+ModulesDirectory [value: path to directory] +

+Specifies the path to modules directory. The MPEG-4 Systems engine cannot be loaded without modules. This option is used by GPAC clients on all platforms. +

+CacheDirectory [value: path to storage directory] +

+Specifies location of temp files. The user must have write access to this location. Although not used by applications, this is used by several modules. +

+StartupFile [value: filename] +

+Specifies file to load upon startup of most clients (Osmo4/MP4Client). If not specified, no file is loaded. +

+ +LogFile [value: filename] +

+Specifies where to output GPAC's log. By default, the logs are written to stdout. Note that GPAC may be compiled without log support. This is not used by MP4Client. +

+Logs [value: tool[:tool]@level:tool[:tool]@level] +

+Specifies log level for each tool. By default, only errors are logged. Available levels are: +

    +
  • quiet : no logging is performed on the tool
  • +
  • error : only errors are logged
  • +
  • warning : warnings are also logged.
  • +
  • info : information messages are also logged
  • +
  • debug : debug messages are also logged
  • +
+
+Available tools are: +
    +
  • core : libgpac core
  • +
  • coding : bitstream formats (audio, video, scene)
  • +
  • container : container formats (ISO File, MPEG-2 TS, AVI, ...)
  • +
  • network : network data exept RTP trafic
  • +
  • rtp : rtp, rtcp and rtsp trafic
  • +
  • author : authoring tools (hint, import, export)
  • +
  • sync : terminal sync layer
  • +
  • codec : terminal codec messages
  • +
  • parser : scene parsers (svg, xmt, bt) and other
  • +
  • media : terminal media object management
  • +
  • scene : scene graph and scene manager
  • +
  • script : scripting engine messages
  • +
  • interact : user interaction messages
  • +
  • compose : composition engine (events, etc)
  • +
  • cache : HTTP cache
  • +
  • mmio : Audio/Video HW I/O management
  • +
  • rti : Run-time info (CPU, mem, ...)
  • +
  • smil : SMIL timing and animation
  • +
  • memory : GPAC memory tracker
  • +
  • audio : Audio renderer and mixers
  • +
  • module : used by some modules
  • +
  • mutex : mutex information
  • +
  • console : console messages, such as script alert() and error notifications
  • +
+

+ +

+

+

+ +Options defined for Osmo4 (Windows version and wxWidgets version):

+Loop [value: "yes" "no"] +

+Specifies whether the presentation has to be restarted when done playing. +

+ConsoleOff [value: "yes" "no"] +

+Specifies whether application messages (script, buffering, download progress) are displayed in the console or not. +

+SingleInstance [value: "yes", "no"] +

+Specifies if the player should be a single instance application or not (Osmo4-Win32 only). +

+LookForSubtitles [value: "yes" "no"] +

+Specifies if Osmo4 shall look for subtitle files when opening a presentation. +

+ViewXMT [value: "yes" "no"] +

+Specifies if scene dumping shall be done in XML (XMT, X3D) or in VRML-like syntax (BT, WRL). +

+ConfigPanel [value: positive integer] +

+Specifies the latest config panel selected by user. +

+NoMIMETypeFetch [value: "yes", "no"] +

+Specifies if the player has to check for mime type when following hyperlinks, or only follow links of known extensions. +

+Loop [value: "yes", "no"] +

+Specifies if the playlist shall be restarted when playback is over. +

+PLEntry [value: positive integer] +

+Indicates active playlist entry when player was last closed. Playlist backup is: +

+
    +
  • "gpac_pl.m3u" on win32 platforms, stored in same directory as application
  • +
  • ".gpac_pl.m3u" on other platforms, stored in user home directory
  • +
+FillScreen [value: "yes", "no"] +

+Specifies if the display area shall fill all available space on screen. WindowsMobile/Symbian only +

+DisableBackLight [value: "yes", "no"] +

+Specifies if the screen backlighting shall be disabled while playing. WindowsMobile/Symbian only +

+LastWorkingDir [value: "yes", "no"] +

+Specifies the directory of the last local file opened. Smartphone Windows only +

+Browser [value: string] +

+Specifies prefered browser for WWW anchors and scene graph viewing - Only used by Osmo4/wxWidgets. +

+ + +Section "RecentFiles" Back to top +

+The "RecentFiles" section of the config file holds last accessed files (hardcoded to no more than 20) in the last access order. The keys are +the file names and no value is used. This section is only used by GUI clients (osmo4/wxOsmo4) +

+ + +Section "Systems" Back to top +

+The "Systems" section of the config file holds all configuration options for the MPEG-4 Systems engine. +

+LanguageName [value: string] +

+Specifies the user prefered language in readable english. This is used to select streams in case of alternate content in an audio object. +

+Language3CC [value: 3-char code from ISO 639-2] +

+Specifies the user prefered language as expressed in ISO 639-2. This is used to select streams in case of alternate content in an audio object. +

+Language2CC [value: 2-char code from ISO 639-1] +

+Specifies the user prefered language as expressed in ISO 639-1. This is used to select streams in case of alternate content in an audio object. +

+DrawLateFrames [value: "yes" "no"] +

+If set, late frames will still be drawn. If not set, the late frames are droped (or executed for systems decoders) untill the decoder output is back in sync. This is by default on to keep better testing heavy content or slow renderers, but should be set to off when needing a better sync or monitoring skipped frames. +

+ForceSingleClock [value: "yes" "no"] +

+One big problem with MP4 files is that the notion of "duration" has been unclear for a long time, and most content available (audio-video files) specifiy a +wrong BIFS duration. In such a case the movie cannot be controled/seeked into. Another problem with ISMA streaming is that BIFS/OD don't use the same clock as +audio/video, thus seeking the main timeline does not seek AV media. Setting the ForceSingleClock will handle both cases by using a single timeline for all media +streams and setting the duration to the one of the longest stream. +

+ThreadingPolicy [value: "Free" "Single" "Multi"] +

+Specifies how media decoders are to be threaded. "Free" lets decoders decide of their threading, "Single" means that all decoders are managed in a single thread performing scheduling and priority +handling and "Multi" means that each decoder runs in its own thread. +

+Priority [value: "low" "normal" "high" "real-time"] +

+Specifies the priority of the decoders (priority is applied to decoder thread(s) regardless of threading mode). +

+TimeSlice [value: unsigned integer] +

+Specifies the target maximum time (in ms) of one cycle of the media manager (the media manager will attempts to call all the active decoders within this time. Depending on the threading mode this option can be ignored; +

+ModuleUnload [value: "yes" "no"] +

+Specifies whether modules should be unloaded if not used or not. Default: "yes". +

+ResyncLateClock [value: unsigned integer] +

+Specifies the threshold after which late clocks are resynchronized to timestamps for OCR streams. By default, no threashold (0) is used and clocks are never resynchronized. This allows to +resync clocks to the media owning the clock when the decoding is really too slow, and should only be used for debugging purposes. +

+NoVisualThread [value: "yes" "no"] +

+Specifies whether the visual rendering is done in the main codec manager or in a dedicated thread. +

+DefAudioDec , DefVideoDec and DefImageDec [value: string] +

+Specifies which module to use by default for audio/video/image decoding. The string is the name of the module to be used (same considerations as other modules, cf introduction). +

+codec_XX_XX [value: string] +

+Allows to specify default media module (audio/video) per stream type and object type. This is usefull if you have more than one decoder for a given type (ex, XviD and FFMPEG for MPEG-4 visual SP). The syntax is: +
codec_AA_BB=modulename
+where AA is the hexadecimal MPEG-4 streamType value for the codec (04=visual, 05=audio) and BB is the hexadecimal MPEG-4 objectTypeIndication of the media (0x20 = MPEG-4 video, 0x40=MPEG-4 Audio, ...). +The string is the name of the module to be used (same considerations as other modules, cf introduction). +

+ + +Section "Compositor" Back to top +

+The "Compositor" section of the config file holds all configuration options for the compositor (logical rendering engine). +

+Raster2D [value: string] +

+Specifies the 2D rasterizer to use for vectorial drawing. Same as above, this module cannot be reloaded during a presentation.

+FrameRate [value: float] +

+Specifies the simulation frame-rate of the presentation - this value is also used by the MPEG-4 Systems engine to determine when a BIFS frame is mature for decoding.

+AntiAlias [value: "None" "All" "Text"] +

+Specifies antialiasing settings - whether the setting is applied or not depends on the graphics module / graphic card. +

+
    +
  • "None": no anti-aliasing
  • +
  • "Text": anti-aliasing for text only
  • +
  • "All": complete anti-aliasing
  • +
+HighSpeed [value: "yes" "no"] +

+Specifies whether rendering should target speed or quality - whether the setting is applied or not depends on the renderer, graphics module / graphic card.

+ForceSceneSize [value: "yes" "no"] +

+Forces the scene to resize to the biggest bitmap available if no size info is given in the BIFS configuration.

+StressMode [value: "yes" "no"] +

+Specifies that the renderer runs in worst case scenario, recomputing display lists and reloading textures (sending them to graphics card) at each frame even when no change has occured.

+BoundingVolume [value: "None" "Box" "AABB"] +

+Specifies whether the bounding volume of an object shall be drawn or not. Note that the 2D renderer only uses rectangles as bounding volumes. The "AABB" value is used by the +3D renderer only, and specifies the object bounding-box tree shall be drawn.

+ColorKey [value: unsigned hexadecimal integer, formated as AARRGGBB] +

+Specifies the color key to use for windowless rendering. GPAC currently doesn't support true alpha blitting to desktop due to limitations in most windowing toolkit, it therefore uses color keying mechanism. The alpha part of the key is used for global transparency of GPAC's output, if supported. +

+BackColor [value: unsigned hexadecimal integer, formated as AARRGGBB] +

+Specifies the background color to use when displaying transparent images or video with no scene compoistion instructions. +

+DrawMode [value: "immediate" "defer" "defer-debug"] +

+Specifies whether immediate drawing should be used or not. In immediate mode, the screen is completely redrawn at each frame. In defer mode +object positioning is tracked from frame to frame and dirty rectangles info is collected in order to redraw the minimal amount of the screen buffer. Whether +the setting is applied or not depends on the graphics module (currently all modules handle both mode). Defer Debug mode only renders changed areas.

+ScalableZoom [value: "yes" "no"] +

+Specifies whether scalable zoom should be used or not. When scalable zoom is enabled, resizing the output window will also recompute all vectorial objects. Otherwise only the final buffer is stretched.

+DisableYUV [value: "yes" "no"] +

+Disables YUV hardware support (YUV hardware support may not be available for the current video output module).

+TextureFromDecoderMemory [value: "yes" "no"] +

+Allows video textures to be build directly from video decoder internal buffers. This may increase performances on some systems. Default is no.

+ForceOpenGL [value: "always", "disable", "hybrid", "raster"] +

+Specifies that 2D rendering will be performed by OpenGL rather than raster 2D. This will involve polygon tesselation which may not be supported on all platforms, and 2D graphics will not loo as nice as 2D mode. The hybrid mode performs software drawing of 2D graphics with no textures (better quality) and uses OpenGL for all textures. The raster mode only uses OpenGL for pixel IO but does not perform polygin fill (no tesselation) (slow, mainly for test purposes).

+EnablePBO [value: "yes", "no"] +

+Uses PixelBufferObjects to push YUV textures to GPU in OpenGL Mode.. This may slightly increase the performances of the playback.

+DefaultNavigationMode [value: "Walk", "Fly", "Examine"] +

+Overrides the default navigation mode of MPEG-4/VRML (Walk) and X3D (Examine).

+RasterOutlines [value: "yes" "no"] +

+Specifies that outlining shall be done through OpenGL pen width rather than vectorial outlining.

+PolygonAA [value: "yes" "no"] +

+Specifies whether polygon antialiasing should be used in full antialiasing mode. If not set, only lines and points antialiasing are used.

+DisableBackFaceCulling [value: "yes" "no"] +

+Specifies whether backface culling shall be disable or not. If not set, backface culling is performed.

+Wireframe [value: "WireNone" "WireOnly" "WireOnSolid"] +

+Specifies wireframe drawing options:

+
    +
  • "WireNone": objects are drawn as solid
  • +
  • "WireOnly": objects are drawn as wireframe only
  • +
  • "WireOnSolid": objects are drawn as solid and wireframe is then drawn
  • +
+DisableRectExt [value: "yes" "no"] +

+Specifies whether OpenGL rectangular texture extension (GL_EXT_texture_rectangle or GL_NV_texture_rectangle) shall be used or not.

+
    +
  • "yes": textures whose dimensions are not power of two are rescaled except if hardware support non-power-of-two textures (GL_ARB_texture_non_power_of_two) natively.
  • +
  • "no": if extension is available, textures are used without rescaling. Note that in this case texture transformations are disabled.
  • +
+EmulatePOW2 [value: "yes" "no"] +

+Enables power of 2 emulation. Ignored if openGL rectangular texture extension is enabled.

+
    +
  • "yes": video texture is not resized but emulated with padding. This usually speeds up video mapping on shapes but disables texture transformations.
  • +
  • "no": video is resized to a power of 2 texture when mapping to a shape.
  • +
+DisableGLUScale [value: "yes" "no"] +

+Disables usage of gluScaleImage, which may be slower but nicer than GPAC's software stretch routines.

+TextureTextMode (value: "Default", "Never", "Always"] +

+Specifies whether text shall be drawn to a texture and then rendered or directly rendered. Using textured text can improve text rendering in 3D and also improve text-on-video like content. Default value will use texturing for OpenGL rendering.

+OpenGLExtensions [value: string] +

+Read-only option listing the OpenGL extensions supported by the GL driver. Only valid after the 3D renderer has been used. +

+StereoType [value: "None", "SideBySide", "TopToBottom", "Anaglyph", "Columns", "Rows", "SPV19", "Custom"] +

+Specifies the stereo output type (default "None"). If your graphic card does not support OpenGL shaders, only SideBySide and TopToBottom modes will be available.

+
    +
  • "SideBySide": images are displayed side by side from left to right.
  • +
  • "TopToBottom": images are displayed from top (laft view) to bottom (right view).
  • +
  • "Anaglyph": Standard color anaglyph (red for left view, green and blue for right view) is used.
  • +
  • "Columns": images are interleaved by columns, left view on even columns and left view on odd columns.
  • +
  • "Rows": images are interleaved by columns, left view on even rows and left view on odd rows.
  • +
  • "SPV19": images are interleaved by for SpatialView 19'' 5 views display, fullscreen mode.
  • +
  • "Custom": images are interleaved according to the shader specified by InterleaverShader +
+ +NumViews [value: unsigned integer] +

+Specifies the number of views to use in stereo mode. If mode is "Anaglyph", "Columns" or "Rows", the number of views is forced to 2.

+ +InterleaverShader [value: path to fragment shader file] +

+Specifies the fragment shader file to use for view interleaving. Each view is rendered in its own texture. The shader is exposed each view as uniform sampler2D gfViewX, where X is the view number starting from the left (gfView1).

+ +ReverseViews [value: "yes", "no"] +

+Specifies if the view order should be reversed (from right to left) or not.

+EyeSeparation [value: float] +

+Specifies the eye separation in cm (distance between the cameras). Default: 6.3 cm.

+CameraLayout [value: "OffAxis", Linear", "Circular"] +

+Specifies the camera layout. The default value is OffAxis in (auto-)stereo modes, ignored in mono mode.

+ViewDistance [value: integer] +

+Specifies the distance in cm between the camera and the zero-disparity plane. There is currently no automatic calibration of depth in GPAC.

+ + +

+ + +Section "Audio" Back to top +

The "Audio" section of the config file holds all configuration options for the audio rendering engine and hardware.

+DriverName [value: string] +

+Specifies the driver to use for audio rendering. This driver cannot be reloaded at run-time, the complete system must be restarted.

+ForceConfig [value: "yes" "no"] +

+Forces a given sound card configuration to be used. If not set the sound card will be setup to use 2 audio buffers of 1024 samples each. +This may not work properly on some audio cards due to hardware latency, therefore forcing the config may be very usefull.

+NumBuffers [value: positive integer, 0 forbidden] +

+When config is forced, specifies the number of audio buffers to allocate (audio buffers are played in ring).

+TotalDuration [value: positive integer, 0 forbidden] +

+When config is forced, specifies the total audio buffer size in milliseconds. Be aware that the longer the audio buffer is, the longer the audio latency will be when pausing an +audio object. The quality of fast forward audio playback will also be degradated when using large audio buffers.

+NoResync [value: "yes" "no"] +

+Disables audio resynchronization: audio data is never dropped but may get out of sync.

+DisableMultiChannel [value: "yes" "no"] +

+Disables audio multichannel output and always downmix to stereo. This may be usefull if the multichannel output behaves weirdly.

+DisableNotification [value: "yes" "no"] +

+Disables usage of audio buffer notifications when supported (currently only DirectSound supports it). If DirectSound audio sounds weird try without notifications.

+Volume [value: integer (0-100)] +

+Default audio volume used when launching GPAC.

+Pan [value: integer (0-100)] +

+Default audio stereo balance used when launching GPAC - 0 for full left, 100 for full right, 50 for balanced.

+Filter [value: string] +

+Defines a set of audio filters. Audio filters are declared as a list of strings separated with ";;". The exact syntax of the string is filter specific.

+ +

+ + +Section "Video" Back to top +

The "Video" section of the config file holds all configuration options for the video renderer and hardware.

+DriverName [value: string] +

+Specifies the driver to use for video memory access. This driver cannot be reloaded at run-time, the complete system must be restarted.

+SwitchResolution [value: "yes" "no"] +

+Specifies fullscreen resolution mode. If enabled, selects smallest video resolution larger than scene size, otherwise use current video resolution.

+HardwareMemory [value: "Auto" "Always" "Never"] +

+Only valid for 2D renderer. Specifies if main video backbuffer is always on hardware, always on system memory or selected by GPAC (default mode). Depending on the scene type, this may drastically change the playback speed.

+DisableColorKeying [value: "yes" "no"] +

+Only valid for 2D renderer. Specifies if partial overlays should be disabled. If not disabled, hardware color keying for overlays is tested and used if present. Otherwise, only the top-most video with no overlapping objects will be drawn using overlays. Default value is "no".

+UseGLDoubleBuffering [value: "yes" "no"] +

+Specifies if OpenGL double buffering shall be used. Default is "no".

+GLNbBitsPerComponent [value: positive integer] +

+Specifies the number of bits per color component. Default is 5.

+GLNbBitsDepth [value: positive integer] +

+Specifies the number of bits for the depth buffer. Default is 16.

+X113DOffscreenMode [value: "Window" "VisibleWindow" "Pixmap"] +

+Specifies the type of OpenGL offscreen rendering in X11. Default mode is "Pixmap".

+
    +
  • "Window": A hidden window is used to perform offscreen rendering. Depending on your video driver and X11 configuration, this may not work.
  • +
  • "VisibleWindow": A visible window is used to perform offscreen rendering. This can be usefull while debugging.
  • +
  • "Pixmap": An X11 Pixmap is used to perform offscreen rendering. Depending on your video driver and X11 configuration, this may not work and can even crash the player.
  • +
+ + +

+ +Section "Network" Back to top +

The "Network" section of the config file holds all configuration options for the network used by modules and systems engine.

+AutoReconfigUDP [value: "yes" "no"] +

+Specifies if network manager shall reconnect a scene if UDP is not present.

+DataTimeout [value: positive integer] +

+Specifies timeout in ms befor initial media buffering aborts. Default terminal value is 20000 (20 seconds).

+UDPNotAvailable [value: "yes" "no"] +

+Specifies if UDP traffic is not available. This is automatically set by GPAC if AutoReconfigUDP is set.

+UDPTimeout [value: positive integer] +

+Specifies timeout in ms for initial UDP detection. Once a UDP packet is recieved the timeout is ignored.

+BufferLength [value: positive integer] +

+Specifies the length of the decoding buffer in milliseconds. The client will wait for the buffer to be filled before starting decoding. A module may decide to use a different value based on protocol and network jitters.

+RebufferLength [value: positive integer] +

+Specifies rebuffering length of the decoding buffer in milliseconds. Whenever the decoding buffer fullness is less than this value, the object clock is paused and +the stream rebuffered till BufferLength. Therefore a value of 0 means no rebuffering. A module may decide to use a different value based on protocol and network jitters. +

+LowLatencyBufferMax [value: positive integer] +

+Specifies the maximum buffer level for low latency mode, in ms. If media buffer max is above this value, full buffering will be done (clock resume at first frame displayed). Default value is 500 ms.

+

+MobileIP [value: IP Address] +

+Specifies a Mobile IP interface overriding the default IP. If set, all sockets will be locally bound to this IP address.

+

+DefaultMCastInterface [value: IP Address] +

+Specifies a default IP interface for Multicast overriding the default IP.If not set, the multicast will be setup using the default IP.

+

+HTTPRebuffer [value: positive integer] +

+Specifies the default HTTP rebuffer time in ms. When playback position reaches download position, playback will be paused if this integer is not zero. Playback will resume once the HTTPRebuffer ms of playback are available. Default value is 5000 ms.

+

+HTTPAutoRebuffer [value: "yes", "no"] +

+Specifies whether auto rebuffering is used. When auto-rebuffering is used, playback only resumes when estimated time to download the rest of the movie is less than remaining time of the playback. Default value is no.

+

+ + + +

+ +Section "FontEngine" Back to top +

The "FontEngine" section of the config file holds all configuration options for the font handling. The GPAC rendering module handles text through vectorial outline, allowing graphics module development without having to +integrate text rendering which is always heavy work.

+FontReader [value: string] +

+Specifies the module to use for font handling. This module cannot be reloaded at run-time, GPAC must be restarted.

+WaitForFontLoad [value: "yes" "no"] +

+Forces to wait for SVG fonts to be loaded before displaying frames - default is "no".

+FontDirectory (value: path to TrueType (*.ttf, *.ttc) font directory] +

+Specifies the directory where fonts are located - currently only one directory can be specified (however nothing stops a font module from using a private directory). +
Note: +The freetype module will scan the entire sub-directories for fonts. +

+FontSerif [value: string]}: specifies default SERIF font.
+FontSans [value: string]}: specifies default SANS font.
+FontFixed [value: string]}: specifies default fixed font.
+
+Note:
+The FreeType module uses this section to cache familly names to font file name associations. + + +

+ +Section "Downloader" Back to top +

The "Downloader" section of the config file holds all configuration options for file downloading and caching.

+CleanCache [value: "yes" "no"] +

+Specifies whether downloaded files shall be removed once used.

+DisableCache [value: "yes" "no"] +

+Specifies whether HTTP caching instructions are disabled or not.

+AllowOfflineCache [value: "yes" "no"] +

+When enabled, allows HTTP request to use cached file if any when network is not available.

+MaxRate [value: positive integer] +

+Specifies a maximum data rate in kilo bits per seconds for file downloading. This is used for simulation purposes. A value of 0 means no rate restriction.

+UserAgent [value: string] +

+Specifies an alternate user agent (default one is "GPAC $VERSION").

+HTTPHeadTimeout [value: positive integer] +

+Specifies timeout in milliseconds before considering HEAD request failed. 0 means no HEAD request is issued, only GET.

+ +

+ +Section "HTTPProxy" Back to top +

The "HTTPProxy" section of the config file holds configuration option for HTTP proxy adressing. Currently only one proxy can be enabled, and no URI selection is done.

+Enabled [value: "yes" "no"] +

+Specifies whether the proxy should be used or not when downloading files.

+Name [value: string] +

+Specifies the proxy name (IP address or resolved name) without protocol identifier (eg, no "http://"). If not present, the proxy is disabled.

+Port [value: positive integer] +

+Specifies the port to use with the proxy. If no port is specified, the default HTTP port (80) is used.

+ +

+ +Section "Streaming" Back to top +

The "Streaming" section of the config file holds all configuration options for real-time streaming using IETF SDP/RTSP/RTP/RTCP protocols.

+DefaultPort [value: unsigned short] +

+Specifies the default port to use when connecting to a server (ignored if a port is specified in the url) if the port is 80 or 8080 (HTTP), the client will connect to the +RTSP server through an HTTP tunnel, and transport will take place on the RTSP connection.

+ReorderSize [value: positive integer] +

+Size of the RTP reordering buffer - 0 means no reordering. Ignored when transport takes place on the RTSP connection. The bigger this value, the longer the reordering delay will be.

+RTPoverRTSP [value: "yes" "no" "OnlyCritical"] +

+Specifies whether RTP packets should be carried on the RTSP connection (TCP or UDP), or carried on UDP. If the connection port is an HTTP port, this value is assumed to be true. If set to OnlyCritical, transport will take place on TCP only if a critical media (eg, neither audio nor video) is found in the session.

+RTSPTimeout [value: positive integer] +

+Specifies connection timeout with the server: an RTSP request is considered as failed when the timeout expires.

+ForceFirstPort [value: positive integer] +

+Specifies first port for RTP channels. If not set, the default first port used by GPAC is 7040.

+NATKeepAlive [value: positive integer] +

+Specifies the maximum inactivity period in milliseconds for RTP sockets. If no data is received after this period, an empty RTP packet will be sent in order to keep any NAT alive. If 0 (default), disables NAT keep-alive packets.

+ForceMulticastIP [value: IP4 or IP6 address] +

+Forces the specified multicast address to be used instead of the regular unicast. Note that some servers may not support multicast initiation by the client.

+ForceMulticastTTL [value: Positive integer] +

+Indicates the TTL to use when the client initiates the multicast. Default value is 127.

+FirstPacketDrop [value: positive integer] +

+Specifies the sequence number of the first RTP packet to be droped - 0 means no packet drop. Used for packet drop simulation tests.

+PacketDropFrequency [value: positive integer] +

+Specifies the frequency at which SL packets are droped. If value is 20, one packet every 20 recieved packets will be droped. Used for packet drop simulation tests.

+ +

+ + +Section "MimeTypes" Back to top +

This section is used to keep MIME types and file associations for GPAC modules. +
The format of the key is: +
mimeType="fileExt1 filexExt2 .. filexExtN" "MimeType description" ModuleName +
+The description is used for GUI purposes (open file dialogs). You may modify the file extension list to support your own extensions. +MIME Type is always checked when processing a remote ressource (eg http file) in order to load the appropriated modules. +If MIME type is not available, provided extensions are first checked, then all input modules are queried. +

+ +

+ + +Section "StreamingCache" Back to top +

The "StreamingCache" section of the config file holds all configuration options for the streaming cache. Streaming cache allows for recording of +live sources such as RTP/RTSP sessions and internet radios. This is currently just an experimental feature in GPAC.

+RecordDirectory [value: path] +

+Specifies path for recorded files. Cached data is written directly to disk (no re-interleaving or similar processes). +If not specified, the default cache directory (cf General) is used.

+BaseFileName [value: string] +

+Specifies the base name for recorded files. If not present in configuration file, the service name (URL) is used.

+KeepExistingFiles [value: "yes" "no"] +

+Specifies if cached files with same name should be kept or not. If not, an integer number is added to the cached file name, the higest number for the latest file.

+ +

+ + +Section "SAXLoader" Back to top +

The "SAXLoader" section of the config file holds all configuration options for XML SAX parsing of SVG, XMT and X3D files.

+Progressive [value: "yes" "no" "DOM"] +

Specifies XML parsing mode used by different file loaders using the SAX parser.

+
    +
  • "yes": SAX parsing is used with progressive loading of the document.
  • +
  • "no": SAX parsing is used, document will first be completely downloaded.
  • +
  • "DOM": DOM parsing is used, document will first be completely downloaded. Only supported by libXML2 plugin, otherwise handled as "no".
  • +
+MaxDuration [value positive integer] +

+Specifies the maximum amount of time the SAX parser should spent loading a portion of the document. Only used with SAX Progressive mode

+ +

+ + +Section "XviD" Back to top +

The "XviD" section of the config file holds all configuration options for the XviD codec.

+PostProc [value: "FilmEffect" "Deblock_Y" "Deblock_UV"] +

+Specifies filters to apply when decoding video. The string is a list of filters separated with a space character.

+
    +
  • "FilmEffect": xvid 1.0.0 filmEffect.
  • +
  • "Deblock_Y": Y plane deblocking filter.
  • +
  • "Deblock_UV": UV plane deblocking filter.
  • +
+Threaded [value "yes" "no"] +

Specifies whether the decoder should run in its own thread or not.

+ +

+ + +Section "FFMPEG" Back to top +

The "FFMPEG" section of the config file holds all configuration options for the FFMPEG demuxer and decoder.

+DataBufferMS [value: positive integer] +

+Specifies the amount of video/audio data (in milliseconds) to be bufferer before starting decoding. For developpers only.

+IOBufferSize [value: positive integer] +

+Specifies the size (in bytes) of the buffer used to fecth data from network (http playback only). Default size is 8192 bytes.

+ +

+ + +Section "ISOReader" Back to top +

The "ISOReader" section of the config file holds all configuration options for the ISO Media File demuxer.

+IgnoreMPEG-4ForBrands [value: Full 4CC or 4CC pattern (abc* ab*)] +

+Ignores all MPEG-4 systems tracks and IOD for files showing the listed brands in their compatible brand list.

+ +

+ + +Section "DVB" Back to top +

The "DVB" section of the config file holds all configuration options for DVB playback on GNU/Linux systems.

+ChannelsFile [value: Absolute file path] +

+Specifies the DVB channels configuration file as produced by dvbtools' scan util.

+ +

+ + +Section "DASH" Back to top +

The "DASH" section of the config file holds all configuration options for DASH or HLS/M3U8 playback.

+KeepFiles [value: yes, no] +

+Specifies whether downloaded files should not be deleted.

+AutoSwitchCount [value: positive integer] +

+For debug purposes, instructs the player to switch representation every N segments. If 0 (default), switching is disabled.

+BufferMode [value: segments, minBuffer, none] +

+Selects buffer mode: +

    +
  • segments: buffers complete segments as indicated in MPD before handing them to the player.
  • +
  • minBuffer: asks the player to buffer media for the time indicated in the MPD (default mode), but segments are not pre-buffered.
  • +
  • none: uses the player settings for buffering.
  • +
+

+DisableSwitching [value: yes, no] +

+Disables automatic adaptation logic. Default is no

+MemoryStorage [value: yes, no] +

+Files are only stored in memory and destroyed after playback, no disk IO is used. Default is yes

+UseMaxResolution [value: yes, no] +

+Forces the player to set the output video resolution to the max resolution available instead of resizing the window. Default is yes

+UseScreenResolution [value: yes, no] +

+Disables all resolutions that are higher than the screen resolution. Default is yes

+StartRepresentation [value: minBandwidth, maxBandwidth, minQuality, maxQuality] +

+Instructs the DASH client to start playing the indicated representation before doing any switching. Default is minBandwidth.

+InitialTimeshift [value: positive integer ] +

+If between 0 and 100, indicates the percentage of the timeshift buffer when starting playback.
+If more than 100, indicates the number of milliseconds to rewind in the timeshift buffer when starting playback.
+Default is 0 to tune to the live point.

+LowLatency [value: always, chunk, no] +

+Sets low-latency mode enabled. In low-latency mode, media data is parsed as soon as possible while segment is being downloaded. Default is no. +If chunk is selected, media data is re-parsed at each HTTP 1.1 chunk end. If always is selected, media data is re-parsed as soon as HTTP data is received.

+AllowAbort [value: yes, no] +

+Enables aborts of HTTP transfer when rate gets too low. This may result in a packet drops. Default is no.

+UseServerUTC [value: yes, no] +

+Enables using Server-UTC HTTP header to compensate any drift between client and server. Default is yes.

+DebugAdaptationSet [value: integer] +

+Plays only the adaptation set indicated by its index in the MPD. If index is negative, all sets are used (default mode). +

+SwitchProbeCount [value: unsigned integer] +

+Sets how many segments the client shall wait before switching up bandwidth. If 0, switch will happen as soon as the bandwidth is enough, but this is more prone to network variations. +Default value is 1. +

+ + + +

+ + +Section "ALSA" Back to top +

The "ALSA" section of the config file holds all configuration options of the ALSA audio output module on GNU/Linux systems.

+DeviceName [value: string] +

+Specifies the ALSA device to use. Default device is "hw:0,0".

+ +

+ + +Section "StreamingText" Back to top +

The "StreamingText" section of the config file holds all configuration options for the 3GPP/MPEG-4 Streaming Text decoder.

+UseTexturing [value: "yes" "no"] +

+Specifies whether the text shall be drawn using an intermediate texture or not.<OutlineText [value: "yes" "no"] +

+Specifies whether the text shall be drawn with a black thin outline or not.

+ + +

+ + +Section "Shortcuts" Back to top +

The "Shortcuts" section of the config file holds all shortcuts in GPAC. You can define a shorcut for an action as:
+'action'='keyname' or 'action'='ctrl+keyname' or 'action'='alt+keyname' or "='action'='ctrl+alt+keyname'
+Shift is not supported as a key modifier, and case is insensitive. +Currently defined actions are as follows:

+Play or Pause
+Stop
+Step
+Exit
+Mute
+VolumeUp
+VolumeDown
+JumpForward
+JumpBackward
+JumpStart
+JumpEnd
+FastForward
+FineForward
+SlowForward
+FastRewind
+FineRewind
+SlowRewind
+Next
+Previous
+ +

+ + +Section "DSMCC" Back to top +

+The "DSMCC" section of the config file holds the configuration option for the processing of DSMCC data. +

+Activated [value: "true" "false"] +

+Specifies if the DSMCC data will be processed (true). It implies creations of directories and files in the temp directory.

+ + +

+ + +Section "OpenHEVC" Back to top +

+The openHEVC section of the config file holds the configuration option for the OpenHEVC decoder. +

+NumThreads [value: unsigned integer] +

+Specifies the number of threads to allocate to the OpenHEVC decoder. Default is the number of detected cores minus one, or one if core detection fails.

+ThreadingType [value: frame , wpp , frame+wpp ] +

+Specifies the threading type for the openHEVC decoder. Default is frame (wpp disabled).

+CBUnits [value: unsigned integer ] +

+Specifies the number of decoded frames in memory before display. Default value is 4.

+PackHFR [value: yes, no ] +

+Packs 4 consecutive frames in a single 4x frame.

+ + +

+ + +Section "DirectFB" Back to top +

+The "DirectFB" section of the config file holds the configuration options for the DirectFB output module. You may also want to check the official documentation. +

+DisableAcceleration [value: "yes" "no"] +

+Forces to disable hardware acceleration.

+DisableDisplay [value: "yes" "no"] +

+Specifies the DisableDisplay parameter value.

+FlipSyncMode [value: "waitsync" "wait" "sync" "swap"] +

+Specifies the flip sync mode.

+DisableBlit [value: "yes" "no"] +

+Forces to disable hardware blitting.

+WindowMode [value: "X11" "SDL"] +

+Specifies the underlying windowing library.

+ + +

+ + +Section "DektecVideo" Back to top +

+The "DektecVideo" section of the config file holds the configuration options for the Dektec SDI video output module. +

+SDIOutput [value: unsigned integer] +

+Specifies the output port of the card. Default value is 1.

+ + + diff --git a/doc/doxyfile b/doc/doxyfile new file mode 100644 index 0000000..bd9c46d --- /dev/null +++ b/doc/doxyfile @@ -0,0 +1,2316 @@ +# Doxyfile 1.8.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = libgpac + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Documentation of the core library of GPAC. For more information, check out http://gpac.wp.mines-telecom.fr" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = ..\regression_tests\auxiliary_files\logo.jpg + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- +# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, +# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, +# Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = NO + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = NO + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = YES + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = YES + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = NO + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note the this +# will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = doxygen_warnings.txt + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = ../include/gpac/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html-libgpac + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /